aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/tests/Makefile13
-rw-r--r--lib/libc/gen/memfd_create.c23
-rw-r--r--lib/libc/gen/sysctl.327
-rw-r--r--lib/libc/tests/string/Makefile2
-rw-r--r--lib/libc/tests/string/strrchr_test.c156
-rw-r--r--lib/libcasper/services/cap_dns/cap_dns.c2
-rw-r--r--lib/libgcc_s/Symbol.map1
-rw-r--r--lib/libifconfig/libifconfig.c4
-rw-r--r--lib/libifconfig/libifconfig_carp.c5
-rw-r--r--lib/libifconfig/libifconfig_sfp.c238
-rw-r--r--lib/libifconfig/libifconfig_sfp.h27
-rw-r--r--lib/libifconfig/sfp.lua120
-rw-r--r--lib/libpfctl/libpfctl.c4
-rw-r--r--lib/libpmc/libpmc_json.cc5
-rw-r--r--lib/libpmc/pmclog.329
-rw-r--r--lib/libpmc/pmclog.c4
-rw-r--r--lib/libpmc/pmclog.h6
-rw-r--r--lib/libsecureboot/h/verify_file.h5
-rw-r--r--lib/libsecureboot/tests/tvo.c6
-rw-r--r--lib/libsecureboot/vectx.c48
-rw-r--r--lib/libsecureboot/verify_file.c3
-rw-r--r--lib/libsys/fork.22
-rw-r--r--lib/libsys/ntp_adjtime.26
-rw-r--r--lib/libsys/shm_open.231
-rw-r--r--lib/libsys/x86/pkru.320
-rw-r--r--lib/libthr/libthr.325
-rw-r--r--lib/libzstd/Makefile4
-rw-r--r--lib/msun/Makefile17
-rw-r--r--lib/msun/Symbol.map12
-rw-r--r--lib/msun/aarch64/Symbol.map10
-rw-r--r--lib/msun/aarch64/fenv.c18
-rw-r--r--lib/msun/aarch64/fenv.h14
-rw-r--r--lib/msun/amd64/Makefile.inc1
-rw-r--r--lib/msun/arm/Makefile.inc1
-rw-r--r--lib/msun/i387/Makefile.inc1
-rw-r--r--lib/msun/man/fmax.39
-rw-r--r--lib/msun/man/fmaximum.34
-rw-r--r--lib/msun/man/fmaximum_mag.3102
-rw-r--r--lib/msun/man/fmaximum_num.3113
-rw-r--r--lib/msun/man/math.312
-rw-r--r--lib/msun/powerpc/Makefile.inc1
-rw-r--r--lib/msun/riscv/Makefile.inc1
-rw-r--r--lib/msun/src/math.h12
-rw-r--r--lib/msun/src/s_fmaximum_mag.c73
-rw-r--r--lib/msun/src/s_fmaximum_magf.c68
-rw-r--r--lib/msun/src/s_fmaximum_magl.c62
-rw-r--r--lib/msun/src/s_fmaximum_num.c74
-rw-r--r--lib/msun/src/s_fmaximum_numf.c70
-rw-r--r--lib/msun/src/s_fmaximum_numl.c63
-rw-r--r--lib/msun/src/s_fminimum.c2
-rw-r--r--lib/msun/src/s_fminimum_mag.c74
-rw-r--r--lib/msun/src/s_fminimum_magf.c69
-rw-r--r--lib/msun/src/s_fminimum_magl.c63
-rw-r--r--lib/msun/src/s_fminimum_num.c76
-rw-r--r--lib/msun/src/s_fminimum_numf.c71
-rw-r--r--lib/msun/src/s_fminimum_numl.c65
-rw-r--r--lib/msun/src/s_fminimumf.c2
-rw-r--r--lib/msun/src/s_fminimuml.c2
-rw-r--r--lib/msun/tests/fmaximum_fminimum_test.c78
59 files changed, 1953 insertions, 103 deletions
diff --git a/lib/libarchive/tests/Makefile b/lib/libarchive/tests/Makefile
index 880c0d3ce0c6..3a03725054f4 100644
--- a/lib/libarchive/tests/Makefile
+++ b/lib/libarchive/tests/Makefile
@@ -131,6 +131,8 @@ TESTS_SRCS= \
test_read_format_ar.c \
test_read_format_cab.c \
test_read_format_cab_filename.c \
+ test_read_format_cab_lzx_oob.c \
+ test_read_format_cab_skip_malformed.c \
test_read_format_cpio_afio.c \
test_read_format_cpio_bin.c \
test_read_format_cpio_bin_Z.c \
@@ -159,6 +161,7 @@ TESTS_SRCS= \
test_read_format_iso_Z.c \
test_read_format_iso_multi_extent.c \
test_read_format_iso_xorriso.c \
+ test_read_format_iso_zisofs_overflow.c \
test_read_format_isorr_rr_moved.c \
test_read_format_isojoliet_bz2.c \
test_read_format_isojoliet_long.c \
@@ -172,10 +175,12 @@ TESTS_SRCS= \
test_read_format_lha_bugfix_0.c \
test_read_format_lha_filename.c \
test_read_format_lha_filename_utf16.c \
+ test_read_format_lha_oversize_header.c \
test_read_format_mtree.c \
test_read_format_mtree_crash747.c \
test_read_format_pax_bz2.c \
test_read_format_rar.c \
+ test_read_format_rar5_loop_bug.c \
test_read_format_rar5.c \
test_read_format_rar_encryption.c \
test_read_format_rar_encryption_data.c \
@@ -242,6 +247,7 @@ TESTS_SRCS= \
test_sparse_basic.c \
test_tar_filenames.c \
test_tar_large.c \
+ test_v7tar_filename_encoding.c \
test_warn_missing_hardlink_target.c \
test_ustar_filenames.c \
test_ustar_filename_encoding.c \
@@ -499,8 +505,10 @@ ${PACKAGE}FILES+= test_read_format_7zip_lzma2_riscv.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma2_sparc.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_malformed.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_malformed2.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_malformed3.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_packinfo_digests.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_ppmd.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_sfx_elf64trunc.elf.uu
${PACKAGE}FILES+= test_read_format_7zip_sfx_elf.elf.uu
${PACKAGE}FILES+= test_read_format_7zip_sfx_modified_pe.exe.uu
${PACKAGE}FILES+= test_read_format_7zip_sfx_pe.exe.uu
@@ -517,6 +525,8 @@ ${PACKAGE}FILES+= test_read_format_cab_1.cab.uu
${PACKAGE}FILES+= test_read_format_cab_2.cab.uu
${PACKAGE}FILES+= test_read_format_cab_3.cab.uu
${PACKAGE}FILES+= test_read_format_cab_filename_cp932.cab.uu
+${PACKAGE}FILES+= test_read_format_cab_lzx_oob.cab.uu
+${PACKAGE}FILES+= test_read_format_cab_skip_malformed.cab.uu
${PACKAGE}FILES+= test_read_format_cpio_bin_be.cpio.uu
${PACKAGE}FILES+= test_read_format_cpio_bin_le.cpio.uu
${PACKAGE}FILES+= test_read_format_cpio_filename_cp866.cpio.uu
@@ -552,6 +562,7 @@ ${PACKAGE}FILES+= test_read_format_iso_rockridge_ce.iso.Z.uu
${PACKAGE}FILES+= test_read_format_iso_rockridge_new.iso.Z.uu
${PACKAGE}FILES+= test_read_format_iso_rockridge_rr_moved.iso.Z.uu
${PACKAGE}FILES+= test_read_format_iso_xorriso.iso.Z.uu
+${PACKAGE}FILES+= test_read_format_iso_zisofs_overflow.iso.uu
${PACKAGE}FILES+= test_read_format_iso_zisofs.iso.Z.uu
${PACKAGE}FILES+= test_read_format_lha_bugfix_0.lzh.uu
${PACKAGE}FILES+= test_read_format_lha_filename_cp932.lzh.uu
@@ -563,6 +574,7 @@ ${PACKAGE}FILES+= test_read_format_lha_header3.lzh.uu
${PACKAGE}FILES+= test_read_format_lha_lh0.lzh.uu
${PACKAGE}FILES+= test_read_format_lha_lh6.lzh.uu
${PACKAGE}FILES+= test_read_format_lha_lh7.lzh.uu
+${PACKAGE}FILES+= test_read_format_lha_oversize_header.lzh.uu
${PACKAGE}FILES+= test_read_format_lha_withjunk.lzh.uu
${PACKAGE}FILES+= test_read_format_mtree.mtree.uu
${PACKAGE}FILES+= test_read_format_mtree_crash747.mtree.bz2.uu
@@ -615,6 +627,7 @@ ${PACKAGE}FILES+= test_read_format_rar5_dirdata.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_distance_overflow.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_encrypted.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_encrypted_filenames.rar.uu
+${PACKAGE}FILES+= test_read_format_rar5_loop_bug.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_solid_encrypted.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_solid_encrypted_filenames.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_extra_field_version.rar.uu
diff --git a/lib/libc/gen/memfd_create.c b/lib/libc/gen/memfd_create.c
index 78131f46d7b1..8e6c93be4337 100644
--- a/lib/libc/gen/memfd_create.c
+++ b/lib/libc/gen/memfd_create.c
@@ -95,16 +95,25 @@ memfd_create(const char *name, unsigned int flags)
npgs = getpagesizes(pgs, nitems(pgs));
if (npgs == -1)
goto clean;
- pgsize = (size_t)1 << ((flags & MFD_HUGE_MASK) >> MFD_HUGE_SHIFT);
- for (pgidx = 0; pgidx < npgs; pgidx++) {
- if (pgsize == pgs[pgidx])
- break;
- }
- if (pgidx == npgs) {
- errno = EOPNOTSUPP;
+ else if (npgs == 1) {
+ errno = ENOSYS;
goto clean;
}
+ if ((flags & MFD_HUGE_MASK) == 0) {
+ pgidx = 1;
+ } else {
+ pgsize = 1UL << ((flags & MFD_HUGE_MASK) >> MFD_HUGE_SHIFT);
+ for (pgidx = 1; pgidx < npgs; pgidx++) {
+ if (pgsize == pgs[pgidx])
+ break;
+ }
+ if (pgidx == npgs) {
+ errno = EOPNOTSUPP;
+ goto clean;
+ }
+ }
+
memset(&slc, 0, sizeof(slc));
slc.psind = pgidx;
slc.alloc_policy = SHM_LARGEPAGE_ALLOC_DEFAULT;
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index ef897c653728..75fd6307bd30 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 31, 2025
+.Dd April 15, 2026
.Dt SYSCTL 3
.Os
.Sh NAME
@@ -325,7 +325,7 @@ information.
.Bl -column "KERNXMAXFILESPERPROCXXX" "struct clockrateXXX" -offset indent
.It Sy Second Level Name Ta Sy Type Ta Sy Changeable
.It Dv KERN_ARGMAX Ta integer Ta no
-.It Dv KERN_ARND Ta integer Ta no
+.It Dv KERN_ARND Ta byte buffer Ta no
.It Dv KERN_BOOTFILE Ta string Ta yes
.It Dv KERN_BOOTTIME Ta struct timeval Ta no
.It Dv KERN_CLOCKRATE Ta struct clockinfo Ta no
@@ -333,7 +333,7 @@ information.
.It Dv KERN_HOSTID Ta integer Ta yes
.It Dv KERN_HOSTUUID Ta string Ta yes
.It Dv KERN_HOSTNAME Ta string Ta yes
-.It Dv KERN_IOV_MAX Ta integer Ta yes
+.It Dv KERN_IOV_MAX Ta integer Ta no
.It Dv KERN_JOB_CONTROL Ta integer Ta no
.It Dv KERN_LOCKF Ta struct kinfo_lockf Ta no
.It Dv KERN_LOGSIGEXIT Ta integer Ta yes
@@ -457,7 +457,7 @@ the currently installed userland.
.It Li KERN_OSRELEASE
The system release string.
.It Li KERN_OSREV
-The system revision string.
+The system revision number.
.It Li KERN_OSTYPE
The system type string.
.It Li KERN_POSIX1
@@ -501,14 +501,14 @@ specifies the current process.
.It Dv KERN_PROC_GROUPS Ta "gid_t []"
.It Dv KERN_PROC_ENV Ta "Set of strings"
.It Dv KERN_PROC_AUXV Ta "Elf_Auxinfo []"
-.It Dv KERN_PROC_RLIMIT Ta "Integer"
-.It Dv KERN_PROC_PS_STRINGS Ta "Integer"
+.It Dv KERN_PROC_RLIMIT Ta "struct rlimit"
+.It Dv KERN_PROC_PS_STRINGS Ta "Pointer to struct ps_strings"
.It Dv KERN_PROC_UMASK Ta "Integer/short"
.It Dv KERN_PROC_OSREL Ta "Integer"
-.It Dv KERN_PROC_SIGTRAMP Ta "Integer"
-.It Dv KERN_PROC_CWD Ta "String"
+.It Dv KERN_PROC_SIGTRAMP Ta "struct kinfo_sigtramp"
+.It Dv KERN_PROC_CWD Ta "struct kinfo_file"
.It Dv KERN_PROC_NFDS Ta "Integer"
-.It Dv KERN_PROC_SIGFASTBLK Ta "Integer"
+.It Dv KERN_PROC_SIGFASTBLK Ta "Address"
.It Dv KERN_PROC_VM_LAYOUT Ta "struct kinfo_vm_layout"
.It Dv KERN_PROC_RLIMIT_USAGE Ta "rlim_t []"
.It Dv KERN_PROC_KQUEUE Ta "struct kinfo_knote []"
@@ -570,7 +570,8 @@ Read from the note of the elf executable at
time.
Might be modified by the process.
.It Dv KERN_PROC_SIGTRAMP
-Address of the signal trampoline in the process address space,
+Structure describing the address range of the signal trampoline in the
+process address space,
where, simplifying, the kernel passes control for signal delivery.
.It Dv KERN_PROC_CWD
Returns the current working directory for the process.
@@ -586,6 +587,12 @@ Fills a structure describing process virtual address space layout.
Like
.Dv KERN_PROC_RLIMIT ,
but instead of the limit, returns the accounted resource usage.
+If the MIB is of the form
+.Li kern.proc.rlimit_usage\&. Ns Va pid ,
+usage values for all resources are returned.
+If the MIB is of the form
+.Li kern.proc.rlimit_usage\&. Ns Va pid Ns \&. Ns Va resource ,
+the usage value for the specified resource is returned.
For resources which do not have a meaningful current value,
.Li \-1
is returned.
diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile
index a019939c30af..a4d23b2dcfe1 100644
--- a/lib/libc/tests/string/Makefile
+++ b/lib/libc/tests/string/Makefile
@@ -20,6 +20,7 @@ ATF_TESTS_C+= strcmp2_test
ATF_TESTS_C+= strcspn_test
ATF_TESTS_C+= strerror2_test
ATF_TESTS_C+= strlcpy_test
+ATF_TESTS_C+= strrchr2_test
ATF_TESTS_C+= strspn_test
ATF_TESTS_C+= strverscmp_test
ATF_TESTS_C+= strxfrm_test
@@ -49,6 +50,7 @@ NETBSD_ATF_TESTS_C+= swab_test
SRCS.memset2_test= memset_test.c
SRCS.strcmp2_test= strcmp_test.c
SRCS.strerror2_test= strerror_test.c
+SRCS.strrchr2_test= strrchr_test.c
.include "../Makefile.netbsd-tests"
diff --git a/lib/libc/tests/string/strrchr_test.c b/lib/libc/tests/string/strrchr_test.c
new file mode 100644
index 000000000000..1c3d912ec3f8
--- /dev/null
+++ b/lib/libc/tests/string/strrchr_test.c
@@ -0,0 +1,156 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023, 2026 Robert Clausecker <fuz@FreeBSD.org>
+ *
+ * Adapted from memrchr_test.c.
+ */
+
+#include <sys/cdefs.h>
+
+#include <dlfcn.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static char *(*strrchr_fn)(const char *, int);
+
+/*
+ * Check that when looking for the character NUL, we find the
+ * string terminator, and not some NUL character after it.
+ */
+ATF_TC_WITHOUT_HEAD(nul);
+ATF_TC_BODY(nul, tc)
+{
+ size_t i, j, k;
+ char buf[1+15+64]; /* offset [0+15] + 64 buffer bytes + sentinels */
+
+ buf[0] = '\0';
+ memset(buf + 1, '-', sizeof(buf) - 1);
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++)
+ for (k = j; k < 64; k++) {
+ buf[i + j + 1] = '\0';
+ buf[i + k + 1] = '\0';
+ ATF_CHECK_EQ(strrchr_fn(buf + i + 1, '\0'), buf + i + j + 1);
+ buf[i + j + 1] = '-';
+ buf[i + k + 1] = '-';
+ }
+}
+
+/*
+ * Check that if the character 'X' does not occur in the string
+ * (but occurs before and after it), we correctly return NULL.
+ */
+ATF_TC_WITHOUT_HEAD(not_found);
+ATF_TC_BODY(not_found, tc)
+{
+ size_t i, j;
+ char buf[1+15+64+2]; /* offset [0..15] + 64 buffer bytes + sentinels */
+
+ buf[0] = 'X';
+ memset(buf + 1, '-', sizeof(buf) - 1);
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++) {
+ buf[i + j + 1] = '\0';
+ buf[i + j + 2] = 'X';
+ ATF_CHECK_EQ(strrchr_fn(buf + i + 1, 'X'), NULL);
+ buf[i + j + 1] = '-';
+ buf[i + j + 2] = '-';
+ }
+}
+
+static void
+do_found_test(char buf[], size_t first, size_t second)
+{
+ /* invariant: first <= second */
+
+ buf[first] = 'X';
+ buf[second] = 'X';
+ ATF_CHECK_EQ(strrchr_fn(buf, 'X'), buf + second);
+ buf[first] = '-';
+ buf[second] = '-';
+}
+
+/*
+ * Check that if the character 'X' occurs in the string multiple
+ * times (i. e. twice), its last encounter is returned.
+ */
+ATF_TC_WITHOUT_HEAD(found);
+ATF_TC_BODY(found, tc)
+{
+ size_t i, j, k, l;
+ char buf[1+15+64+2];
+
+ buf[0] = 'X';
+ memset(buf + 1, '-', sizeof(buf) - 1);
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++)
+ for (k = 0; k < j; k++)
+ for (l = 0; l <= k; l++) {
+ buf[i + j + 1] = '\0';
+ buf[i + j + 2] = 'X';
+ do_found_test(buf + i + 1, l, k);
+ buf[i + j + 1] = '-';
+ buf[i + j + 2] = '-';
+ }
+}
+
+static void
+do_values_test(char buf[], size_t len, size_t i, int c)
+{
+ /* sentinels */
+ buf[-1] = c;
+ buf[len] = '\0';
+ buf[len + 1] = 'c';
+
+ /* fill the string with some other character, but not with NUL */
+ memset(buf, c == UCHAR_MAX ? c - 1 : c + 1, len);
+
+ if (i < len) {
+ buf[i] = c;
+ ATF_CHECK_EQ(strrchr_fn(buf, c), buf + i);
+ } else
+ ATF_CHECK_EQ(strrchr_fn(buf, c), c == 0 ? buf + len : NULL);
+}
+
+/*
+ * Check that the character is found regardless of its value.
+ * This catches arithmetic (overflow) errors in incorrect SWAR
+ * implementations of byte-parallel character matching.
+ */
+ATF_TC_WITHOUT_HEAD(values);
+ATF_TC_BODY(values, tc)
+{
+ size_t i, j, k;
+ int c;
+ char buf[1+15+64+2];
+
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 64; j++)
+ for (k = 0; k <= j; k++)
+ for (c = 0; c <= UCHAR_MAX; c++)
+ do_values_test(buf + i + 1, j, k, c);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ void *dl_handle;
+
+ dl_handle = dlopen(NULL, RTLD_LAZY);
+ strrchr_fn = dlsym(dl_handle, "test_strrchr");
+ if (strrchr_fn == NULL)
+ strrchr_fn = strrchr;
+
+ ATF_TP_ADD_TC(tp, nul);
+ ATF_TP_ADD_TC(tp, not_found);
+ ATF_TP_ADD_TC(tp, found);
+ ATF_TP_ADD_TC(tp, values);
+
+ return (atf_no_error());
+}
diff --git a/lib/libcasper/services/cap_dns/cap_dns.c b/lib/libcasper/services/cap_dns/cap_dns.c
index 8681f0baef40..8e660b197e3a 100644
--- a/lib/libcasper/services/cap_dns/cap_dns.c
+++ b/lib/libcasper/services/cap_dns/cap_dns.c
@@ -267,7 +267,7 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
}
nvlist_destroy(nvl);
if (curai == NULL && nvlai != NULL) {
- if (firstai == NULL)
+ if (firstai != NULL)
freeaddrinfo(firstai);
return (EAI_MEMORY);
}
diff --git a/lib/libgcc_s/Symbol.map b/lib/libgcc_s/Symbol.map
index e8f7e824adaf..91fdeac3f2cf 100644
--- a/lib/libgcc_s/Symbol.map
+++ b/lib/libgcc_s/Symbol.map
@@ -198,6 +198,7 @@ GCC_4.6.0 {
__divtf3;
__eqtf2;
__extenddftf2;
+ __extendhftf2;
__extendsftf2;
__fixtfdi;
__fixtfsi;
diff --git a/lib/libifconfig/libifconfig.c b/lib/libifconfig/libifconfig.c
index f844ae235a71..bc0fcb6021b2 100644
--- a/lib/libifconfig/libifconfig.c
+++ b/lib/libifconfig/libifconfig.c
@@ -562,7 +562,9 @@ ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
(strncmp(name, "vlan",
strlen("vlan")) == 0) ||
(strncmp(name, "vxlan",
- strlen("vxlan")) == 0)) {
+ strlen("vxlan")) == 0) ||
+ (strncmp(name, "geneve",
+ strlen("geneve")) == 0)) {
h->error.errtype = OTHER;
h->error.errcode = ENOSYS;
return (-1);
diff --git a/lib/libifconfig/libifconfig_carp.c b/lib/libifconfig/libifconfig_carp.c
index 59faa8def496..8599470cd3f9 100644
--- a/lib/libifconfig/libifconfig_carp.c
+++ b/lib/libifconfig/libifconfig_carp.c
@@ -53,7 +53,7 @@ static struct snl_attr_parser ap_carp_get[] = {
{ .type = CARP_NL_STATE, .off = _OUT(carpr_state), .cb = snl_attr_get_uint32 },
{ .type = CARP_NL_ADVBASE, .off = _OUT(carpr_advbase), .cb = snl_attr_get_int32 },
{ .type = CARP_NL_ADVSKEW, .off = _OUT(carpr_advskew), .cb = snl_attr_get_int32 },
- { .type = CARP_NL_KEY, .off = _OUT(carpr_key), .cb = snl_attr_copy_string, .arg_u32 = CARP_KEY_LEN },
+ { .type = CARP_NL_KEY, .off = _OUT(carpr_key), .cb = snl_attr_get_bytes, .arg_u32 = CARP_KEY_LEN },
{ .type = CARP_NL_ADDR, .off = _OUT(carpr_addr), .cb = snl_attr_get_in_addr },
{ .type = CARP_NL_ADDR6, .off = _OUT(carpr_addr6), .cb = snl_attr_get_in6_addr },
{ .type = CARP_NL_VERSION, .off = _OUT(carpr_version), .cb = snl_attr_get_uint8 },
@@ -177,7 +177,8 @@ ifconfig_carp_set_info(ifconfig_handle_t *h, const char *name,
&carpr->carpr_addr);
snl_add_msg_attr(&nw, CARP_NL_ADDR6, sizeof(carpr->carpr_addr6),
&carpr->carpr_addr6);
- snl_add_msg_attr_string(&nw, CARP_NL_KEY, carpr->carpr_key);
+ snl_add_msg_attr(&nw, CARP_NL_KEY, sizeof(carpr->carpr_key),
+ carpr->carpr_key);
snl_add_msg_attr_u8(&nw, CARP_NL_VERSION, carpr->carpr_version);
snl_add_msg_attr_u8(&nw, CARP_NL_VRRP_PRIORITY, carpr->carpr_vrrp_prio);
snl_add_msg_attr_u16(&nw, CARP_NL_VRRP_ADV_INTER, carpr->carpr_vrrp_adv_inter);
diff --git a/lib/libifconfig/libifconfig_sfp.c b/lib/libifconfig/libifconfig_sfp.c
index 1ba6d231a992..a2cddf89a13a 100644
--- a/lib/libifconfig/libifconfig_sfp.c
+++ b/lib/libifconfig/libifconfig_sfp.c
@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <net/if.h>
+#include <net/cmis.h>
#include <net/sff8436.h>
#include <net/sff8472.h>
@@ -114,6 +115,50 @@ read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
return (0);
}
+/*
+ * Reads i2c data with CMIS page/bank selection.
+ * For upper memory (offset >= 128), the page and bank fields select
+ * which CMIS register page is mapped into the 128-255 address range.
+ */
+static int
+read_i2c_page(struct i2c_info *ii, uint8_t addr, uint8_t page, uint8_t bank,
+ uint8_t off, uint8_t len, uint8_t *buf)
+{
+ struct ifi2creq req;
+ int i, l;
+
+ if (ii->error != 0)
+ return (ii->error);
+
+ ii->ifr.ifr_data = (caddr_t)&req;
+
+ i = 0;
+ l = 0;
+ memset(&req, 0, sizeof(req));
+ req.dev_addr = addr;
+ req.offset = off;
+ req.len = len;
+ req.page = page;
+ req.bank = bank;
+
+ while (len > 0) {
+ l = MIN(sizeof(req.data), len);
+ req.len = l;
+ if (ifconfig_ioctlwrap(ii->h, AF_LOCAL, SIOCGI2CPB,
+ &ii->ifr) != 0) {
+ ii->error = errno;
+ return (errno);
+ }
+
+ memcpy(&buf[i], req.data, l);
+ len -= l;
+ i += l;
+ req.offset += l;
+ }
+
+ return (0);
+}
+
static int
i2c_info_init(struct i2c_info *ii, ifconfig_handle_t *h, const char *name)
{
@@ -193,18 +238,76 @@ get_qsfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
return (ii->error);
}
+static int
+get_cmis_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
+{
+ uint8_t app_desc[CMIS_APP_DESC_SIZE];
+ uint8_t dpconfig, appsel;
+ uint8_t app_off;
+
+ /* Module ID from lower memory byte 0 */
+ read_i2c(ii, CMIS_BASE, CMIS_ID, 1, &sfp->sfp_id);
+
+ /* Connector type from Page 00h byte 203 */
+ read_i2c_page(ii, CMIS_BASE, 0x00, 0,
+ CMIS_P0_CONNECTOR, 1, &sfp->sfp_conn);
+
+ /* Media type from lower memory byte 85 */
+ read_i2c(ii, CMIS_BASE, CMIS_MEDIA_TYPE, 1,
+ &sfp->sfp_cmis_media_type);
+
+ /*
+ * Read the active AppSel code from the Active Control Set
+ * (Page 11h, byte 206, bits 7:4). This tells us which
+ * Application Descriptor is actually in use.
+ * AppSel is 1-based; 0 means no application selected.
+ */
+ dpconfig = 0;
+ read_i2c_page(ii, CMIS_BASE, 0x11, 0,
+ CMIS_P11_ACS_DPCONFIG1, 1, &dpconfig);
+ appsel = (dpconfig & CMIS_ACS_APPSEL_MASK) >> CMIS_ACS_APPSEL_SHIFT;
+
+ /* Fall back to first descriptor if AppSel is 0 or out of range */
+ if (appsel == 0 || appsel > CMIS_MAX_APP_DESC)
+ appsel = 1;
+
+ /* Read the active Application Descriptor */
+ app_off = CMIS_APP_DESC_START + (appsel - 1) * CMIS_APP_DESC_SIZE;
+ read_i2c(ii, CMIS_BASE, app_off, CMIS_APP_DESC_SIZE, app_desc);
+ if (ii->error != 0)
+ return (ii->error);
+
+ /* Store MediaInterfaceID based on media type */
+ switch (sfp->sfp_cmis_media_type) {
+ case SFP_CMIS_MEDIA_TYPE_SMF:
+ sfp->sfp_cmis_smf = app_desc[CMIS_APP_MEDIA_IF_ID];
+ break;
+ case SFP_CMIS_MEDIA_TYPE_MMF:
+ sfp->sfp_cmis_mmf = app_desc[CMIS_APP_MEDIA_IF_ID];
+ break;
+ }
+
+ /* Extract media lane count from app descriptor byte 2, bits 3:0 */
+ sfp->sfp_cmis_lanes = app_desc[CMIS_APP_LANE_COUNT] & 0x0F;
+
+ return (ii->error);
+}
+
int
ifconfig_sfp_get_sfp_info(ifconfig_handle_t *h,
const char *name, struct ifconfig_sfp_info *sfp)
{
struct i2c_info ii;
- char buf[8];
+ uint8_t buf[8];
memset(sfp, 0, sizeof(*sfp));
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
+ if (ifconfig_sfp_id_is_cmis(ii.id))
+ return (get_cmis_info(&ii, sfp));
+
/* Read bytes 3-10 at once */
read_i2c(&ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, buf);
if (ii.error != 0)
@@ -246,6 +349,12 @@ channel_count(enum sfp_id id)
size_t
ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp)
{
+ /* CMIS modules: use lane count from Application Descriptor */
+ if (ifconfig_sfp_id_is_cmis(sfp->sfp_id)) {
+ if (sfp->sfp_cmis_lanes > 0)
+ return (sfp->sfp_cmis_lanes);
+ return (0);
+ }
return (channel_count(sfp->sfp_id));
}
@@ -256,7 +365,7 @@ ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp)
static void
get_sff_string(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
{
- read_i2c(ii, addr, off, SFF_VENDOR_STRING_SIZE, dst);
+ read_i2c(ii, addr, off, SFF_VENDOR_STRING_SIZE, (uint8_t *)dst);
dst += SFF_VENDOR_STRING_SIZE;
do { *dst-- = '\0'; } while (*dst == 0x20);
}
@@ -264,7 +373,7 @@ get_sff_string(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
static void
get_sff_date(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
{
- char buf[SFF_VENDOR_DATE_SIZE];
+ uint8_t buf[SFF_VENDOR_DATE_SIZE];
read_i2c(ii, addr, off, SFF_VENDOR_DATE_SIZE, buf);
sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
@@ -291,6 +400,41 @@ get_qsfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
return (ii->error);
}
+/*
+ * Read CMIS vendor strings from Page 00h (upper memory).
+ * Vendor info uses the same ASCII format as SFF-8436 but at
+ * different offsets and requires page selection.
+ */
+static void
+get_cmis_string(struct i2c_info *ii, uint8_t off, char *dst)
+{
+ read_i2c_page(ii, CMIS_BASE, 0x00, 0, off,
+ SFF_VENDOR_STRING_SIZE, dst);
+ dst += SFF_VENDOR_STRING_SIZE;
+ do { *dst-- = '\0'; } while (*dst == 0x20);
+}
+
+static void
+get_cmis_date(struct i2c_info *ii, uint8_t off, char *dst)
+{
+ char buf[SFF_VENDOR_DATE_SIZE];
+
+ read_i2c_page(ii, CMIS_BASE, 0x00, 0, off,
+ SFF_VENDOR_DATE_SIZE, buf);
+ sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5]);
+}
+
+static int
+get_cmis_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
+{
+ get_cmis_string(ii, CMIS_P0_VENDOR_NAME, vi->name);
+ get_cmis_string(ii, CMIS_P0_VENDOR_PN, vi->pn);
+ get_cmis_string(ii, CMIS_P0_VENDOR_SN, vi->sn);
+ get_cmis_date(ii, CMIS_P0_DATE_CODE, vi->date);
+ return (ii->error);
+}
+
int
ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h,
const char *name, struct ifconfig_sfp_vendor_info *vi)
@@ -302,6 +446,8 @@ ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h,
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
+ if (ifconfig_sfp_id_is_cmis(ii.id))
+ return (get_cmis_vendor_info(&ii, vi));
if (ifconfig_sfp_id_is_qsfp(ii.id))
return (get_qsfp_vendor_info(&ii, vi));
return (get_sfp_vendor_info(&ii, vi));
@@ -386,7 +532,7 @@ get_sfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
uint8_t diag_type, flags;
/* Read diagnostic monitoring type */
- read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, &diag_type);
if (ii->error != 0)
return (-1);
@@ -457,6 +603,47 @@ get_qsfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
return (ii->error);
}
+/*
+ * Read CMIS module status: temperature and voltage from lower memory,
+ * per-lane TX power, TX bias, and RX power from Page 11h Bank 0.
+ */
+static int
+get_cmis_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss,
+ size_t channels)
+{
+ /* Temperature and voltage are in lower memory (same format as SFF) */
+ ss->temp = get_sff_temp(ii, CMIS_BASE, CMIS_TEMP);
+ ss->voltage = get_sff_voltage(ii, CMIS_BASE, CMIS_VCC);
+
+ if (channels == 0)
+ return (ii->error);
+
+ ss->channel = calloc(channels, sizeof(*ss->channel));
+ if (ss->channel == NULL) {
+ ii->h->error.errtype = OTHER;
+ ii->h->error.errcode = ENOMEM;
+ return (-1);
+ }
+
+ /* Read per-lane monitors from Page 11h Bank 0 */
+ for (size_t chan = 0; chan < channels; ++chan) {
+ uint8_t off;
+ uint8_t buf[2];
+
+ /* RX optical power */
+ off = CMIS_P11_RX_PWR_1 + chan * CMIS_LANE_MON_SIZE;
+ read_i2c_page(ii, CMIS_BASE, 0x11, 0, off, 2, buf);
+ ss->channel[chan].rx = (buf[0] << 8) | buf[1];
+
+ /* TX bias current */
+ off = CMIS_P11_TX_BIAS_1 + chan * CMIS_LANE_MON_SIZE;
+ read_i2c_page(ii, CMIS_BASE, 0x11, 0, off, 2, buf);
+ ss->channel[chan].tx = (buf[0] << 8) | buf[1];
+ }
+
+ return (ii->error);
+}
+
int
ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
struct ifconfig_sfp_status *ss)
@@ -468,6 +655,20 @@ ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
+ if (ifconfig_sfp_id_is_cmis(ii.id)) {
+ /*
+ * For CMIS, we need the lane count from the module info.
+ * Read the first Application Descriptor to get it.
+ */
+ uint8_t app_desc[CMIS_APP_DESC_SIZE];
+ size_t channels;
+
+ read_i2c(&ii, CMIS_BASE, CMIS_APP_DESC_START,
+ CMIS_APP_DESC_SIZE, app_desc);
+ channels = app_desc[CMIS_APP_LANE_COUNT] & 0x0F;
+ return (get_cmis_status(&ii, ss, channels));
+ }
+
if (ifconfig_sfp_id_is_qsfp(ii.id))
return (get_qsfp_status(&ii, ss));
return (get_sfp_status(&ii, ss));
@@ -527,6 +728,21 @@ const char *
ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info *sfp,
const struct ifconfig_sfp_info_strings *strings)
{
+ /* CMIS modules: look up media interface ID based on media type */
+ if (ifconfig_sfp_id_is_cmis(sfp->sfp_id)) {
+ switch (sfp->sfp_cmis_media_type) {
+ case SFP_CMIS_MEDIA_TYPE_SMF:
+ if (strings->sfp_cmis_smf != NULL)
+ return (strings->sfp_cmis_smf);
+ break;
+ case SFP_CMIS_MEDIA_TYPE_MMF:
+ if (strings->sfp_cmis_mmf != NULL)
+ return (strings->sfp_cmis_mmf);
+ break;
+ }
+ return ("Unknown");
+ }
+
switch (sfp->sfp_id) {
case SFP_ID_UNKNOWN:
break;
@@ -557,12 +773,19 @@ ifconfig_sfp_get_sfp_dump(ifconfig_handle_t *h, const char *name,
struct i2c_info ii;
uint8_t *buf = dump->data;
- memset(dump->data, 0, sizeof(dump->data));
+ memset(buf, 0, sizeof(dump->data));
if (i2c_info_init(&ii, h, name) != 0)
return (-1);
- if (ifconfig_sfp_id_is_qsfp(ii.id)) {
+ if (ifconfig_sfp_id_is_cmis(ii.id)) {
+ /* Lower memory (0-127), Page 00h (128-255), Page 11h */
+ read_i2c(&ii, CMIS_BASE, 0, 128, buf);
+ read_i2c_page(&ii, CMIS_BASE, 0x00, 0, 128, 128,
+ buf + 128);
+ read_i2c_page(&ii, CMIS_BASE, 0x11, 0, 128, 128,
+ buf + CMIS_DUMP_P11);
+ } else if (ifconfig_sfp_id_is_qsfp(ii.id)) {
read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP0_START, QSFP_DUMP0_SIZE,
buf + QSFP_DUMP0_START);
read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP1_START, QSFP_DUMP1_SIZE,
@@ -580,6 +803,9 @@ ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump *dp)
{
uint8_t id_byte = dp->data[0];
+ if (ifconfig_sfp_id_is_cmis((enum sfp_id)id_byte))
+ return (3);
+
switch ((enum sfp_id)id_byte) {
case SFP_ID_UNKNOWN:
return (0);
diff --git a/lib/libifconfig/libifconfig_sfp.h b/lib/libifconfig/libifconfig_sfp.h
index 2e5374d6729e..9ed4f684e5c4 100644
--- a/lib/libifconfig/libifconfig_sfp.h
+++ b/lib/libifconfig/libifconfig_sfp.h
@@ -83,11 +83,15 @@ struct ifconfig_sfp_status {
#define QSFP_DUMP1_SIZE 128 /**< bytes in the second region
in a QSFP module dump */
+#define CMIS_DUMP_SIZE 512 /**< CMIS dump buffer size */
+#define CMIS_DUMP_P11 256 /**< offset of Page 11h in dump buffer */
+
/** SFP module I2C memory dump
- * SFP modules have one region, QSFP modules have two regions.
+ * SFP modules have one region, QSFP modules have two.
+ * CMIS modules have three: lower memory, Page 00h, and Page 11h.
*/
struct ifconfig_sfp_dump {
- uint8_t data[SFF_DUMP_SIZE]; /**< memory dump data */
+ uint8_t data[CMIS_DUMP_SIZE]; /**< memory dump data */
};
/** Get information about the static properties of an SFP/QSFP module
@@ -126,6 +130,25 @@ ifconfig_sfp_id_is_qsfp(enum sfp_id id)
}
}
+/** Is the given module ID a CMIS-managed module (QSFP-DD, OSFP, etc.)
+ * @param id The sfp_id field of a SFP module info object
+ * @return A bool true if CMIS-type sfp_id otherwise false
+ */
+static inline bool
+ifconfig_sfp_id_is_cmis(enum sfp_id id)
+{
+ switch (id) {
+ case SFP_ID_QSFP_DD:
+ case SFP_ID_QSFP8X:
+ case SFP_ID_SFP_DD:
+ case SFP_ID_DSFP:
+ case SFP_ID_QSFP_CMIS:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
/** Get string descriptions of the given SFP/QSFP module info
* The strings are static and do not need to be freed.
* @see ifconfig_sfp_get_sfp_info to obtain the input info.
diff --git a/lib/libifconfig/sfp.lua b/lib/libifconfig/sfp.lua
index 4a43b2ed780b..1da49e35cade 100644
--- a/lib/libifconfig/sfp.lua
+++ b/lib/libifconfig/sfp.lua
@@ -359,6 +359,126 @@ enums = {
{0x0, "UNSPECIFIED", "Unspecified"},
},
},
+
+ "CMIS (OIF-CMIS-05.3) Media Type Encodings (Table 8-20)",
+ {
+ name = "cmis_media_type",
+ description = "CMIS media type",
+ bits = 8,
+ values = {
+ {0x00, "UNDEFINED", "Undefined"},
+ {0x01, "MMF", "Optical: MMF"},
+ {0x02, "SMF", "Optical: SMF"},
+ {0x03, "COPPER", "Passive/Linear Active Copper"},
+ {0x04, "ACTIVE", "Active Cable"},
+ {0x05, "BASET", "BASE-T"},
+ },
+ },
+
+ "CMIS Media Lane Count (from Application Descriptor)",
+ {
+ name = "cmis_lanes",
+ description = "CMIS media lane count",
+ bits = 8,
+ values = {
+ {0, "UNKNOWN", "Unknown"},
+ {1, "1", "1 lane"},
+ {2, "2", "2 lanes"},
+ {4, "4", "4 lanes"},
+ {8, "8", "8 lanes"},
+ },
+ },
+
+ "SFF-8024 Table 4-7: SMF Media Interface IDs (for CMIS MediaType=02h)",
+ "Verified against SFF-8024 Rev 4.6+ and SONiC sff8024.py",
+ {
+ name = "cmis_smf",
+ description = "CMIS SMF media interface",
+ bits = 8,
+ values = {
+ {0x00, "UNDEFINED", "Undefined"},
+ {0x01, "10GBASE_LW", "10GBASE-LW"},
+ {0x02, "10GBASE_EW", "10GBASE-EW"},
+ {0x03, "10G_ZW", "10G-ZW"},
+ {0x04, "10GBASE_LR", "10GBASE-LR"},
+ {0x05, "10GBASE_ER", "10GBASE-ER"},
+ {0x06, "10G_ZR", "10G-ZR"},
+ {0x07, "25GBASE_LR", "25GBASE-LR"},
+ {0x08, "25GBASE_ER", "25GBASE-ER"},
+ {0x09, "40GBASE_LR4", "40GBASE-LR4"},
+ {0x0A, "40GBASE_FR", "40GBASE-FR"},
+ {0x0B, "50GBASE_FR", "50GBASE-FR"},
+ {0x0C, "50GBASE_LR", "50GBASE-LR"},
+ {0x0D, "100GBASE_LR4", "100GBASE-LR4"},
+ {0x0E, "100GBASE_ER4", "100GBASE-ER4"},
+ {0x0F, "100G_PSM4", "100G PSM4"},
+ {0x10, "100G_CWDM4", "100G CWDM4"},
+ {0x11, "100G_4WDM_10", "100G 4WDM-10"},
+ {0x12, "100G_4WDM_20", "100G 4WDM-20"},
+ {0x13, "100G_4WDM_40", "100G 4WDM-40"},
+ {0x14, "100GBASE_DR", "100GBASE-DR"},
+ {0x15, "100G_FR", "100G-FR/100GBASE-FR1"},
+ {0x16, "100G_LR", "100G-LR/100GBASE-LR1"},
+ {0x17, "200GBASE_DR4", "200GBASE-DR4"},
+ {0x18, "200GBASE_FR4", "200GBASE-FR4"},
+ {0x19, "200GBASE_LR4", "200GBASE-LR4"},
+ {0x1A, "400GBASE_FR8", "400GBASE-FR8"},
+ {0x1B, "400GBASE_LR8", "400GBASE-LR8"},
+ {0x1C, "400GBASE_DR4", "400GBASE-DR4"},
+ {0x1D, "400G_FR4", "400G-FR4/400GBASE-FR4"},
+ {0x1E, "400G_LR4_10", "400G-LR4-10"},
+ {0x1F, "8GFC_SM", "8GFC-SM"},
+ {0x20, "10GFC_SM", "10GFC-SM"},
+ {0x21, "16GFC_SM", "16GFC-SM"},
+ {0x22, "32GFC_SM", "32GFC-SM"},
+ {0x23, "64GFC_SM", "64GFC-SM"},
+ {0x24, "128GFC_PSM4", "128GFC-PSM4"},
+ {0x25, "256GFC_PSM4", "256GFC-PSM4"},
+ {0x34, "100G_CWDM4_OCP", "100G CWDM4-OCP"},
+ {0x3E, "400ZR_DWDM", "400ZR DWDM"},
+ {0x40, "50GBASE_ER", "50GBASE-ER"},
+ {0x41, "200GBASE_ER4", "200GBASE-ER4"},
+ {0x42, "400GBASE_ER8", "400GBASE-ER8"},
+ {0x43, "400GBASE_LR4_6", "400GBASE-LR4-6"},
+ },
+ },
+
+ "SFF-8024 Table 4-6: MMF Media Interface IDs (for CMIS MediaType=01h)",
+ "Verified against SFF-8024 Rev 4.6+ and SONiC sff8024.py",
+ {
+ name = "cmis_mmf",
+ description = "CMIS MMF media interface",
+ bits = 8,
+ values = {
+ {0x00, "UNDEFINED", "Undefined"},
+ {0x01, "10GBASE_SW", "10GBASE-SW"},
+ {0x02, "10GBASE_SR", "10GBASE-SR"},
+ {0x03, "25GBASE_SR", "25GBASE-SR"},
+ {0x04, "40GBASE_SR4", "40GBASE-SR4"},
+ {0x05, "40GE_SWDM4", "40GE SWDM4"},
+ {0x06, "40GE_BIDI", "40GE BiDi"},
+ {0x07, "50GBASE_SR", "50GBASE-SR"},
+ {0x08, "100GBASE_SR10", "100GBASE-SR10"},
+ {0x09, "100GBASE_SR4", "100GBASE-SR4"},
+ {0x0A, "100GE_SWDM4", "100GE SWDM4"},
+ {0x0B, "100GE_BIDI", "100GE BiDi"},
+ {0x0C, "100GBASE_SR2", "100GBASE-SR2"},
+ {0x0D, "100G_SR", "100G-SR"},
+ {0x0E, "200GBASE_SR4", "200GBASE-SR4"},
+ {0x0F, "400GBASE_SR16", "400GBASE-SR16"},
+ {0x10, "400GBASE_SR8", "400GBASE-SR8"},
+ {0x11, "400G_SR4", "400G-SR4"},
+ {0x12, "800G_SR8", "800G-SR8"},
+ {0x13, "8GFC_MM", "8GFC-MM"},
+ {0x14, "10GFC_MM", "10GFC-MM"},
+ {0x15, "16GFC_MM", "16GFC-MM"},
+ {0x16, "32GFC_MM", "32GFC-MM"},
+ {0x17, "64GFC_MM", "64GFC-MM"},
+ {0x18, "128GFC_MM4", "128GFC-MM4"},
+ {0x19, "256GFC_MM4", "256GFC-MM4"},
+ {0x1A, "400GBASE_SR4_2", "400GBASE-SR4.2"},
+ },
+ },
}
-- Nothing else in this context.
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index cd484949e4da..59783592a370 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -4084,7 +4084,7 @@ pfctl_state_limiter_add(struct pfctl_handle *h, struct pfctl_state_lim *lim)
return (ENXIO);
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
- if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, &lim))
+ if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, lim))
continue;
}
@@ -4153,7 +4153,7 @@ pfctl_source_limiter_add(struct pfctl_handle *h, struct pfctl_source_lim *lim)
return (ENXIO);
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
- if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, &lim))
+ if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, lim))
continue;
}
diff --git a/lib/libpmc/libpmc_json.cc b/lib/libpmc/libpmc_json.cc
index 90881f22971e..1ac0b3a50a6c 100644
--- a/lib/libpmc/libpmc_json.cc
+++ b/lib/libpmc/libpmc_json.cc
@@ -74,8 +74,8 @@ startentry(struct pmclog_ev *ev)
{
char eventbuf[128];
- snprintf(eventbuf, sizeof(eventbuf), "%s, \"tsc\": \"%jd\"",
- typenames[ev->pl_type], (uintmax_t)ev->pl_ts.tv_sec);
+ snprintf(eventbuf, sizeof(eventbuf), "%s, \"tsc\": \"%ju\"",
+ typenames[ev->pl_type], (uintmax_t)ev->pl_tsc);
return (string(eventbuf));
}
@@ -393,4 +393,3 @@ event_to_json(struct pmclog_ev *ev){
errx(EX_USAGE, "ERROR: unrecognized event type: %d\n", ev->pl_type);
}
}
-
diff --git a/lib/libpmc/pmclog.3 b/lib/libpmc/pmclog.3
index 4af4150d60a9..452a14f42f55 100644
--- a/lib/libpmc/pmclog.3
+++ b/lib/libpmc/pmclog.3
@@ -77,7 +77,10 @@ struct pmclog_ev {
enum pmclog_state pl_state; /* parser state after 'get_event()' */
off_t pl_offset; /* byte offset in stream */
size_t pl_count; /* count of records so far */
- struct timespec pl_ts; /* log entry timestamp */
+ union {
+ uint64_t pl_tsc; /* TSC timestamp */
+ struct timespec pl_ts; /* log entry timestamp (legacy) */
+ };
enum pmclog_type pl_type; /* log entry kind */
union { /* log entry data */
struct pmclog_ev_callchain pl_cc;
@@ -136,8 +139,30 @@ Field
.Va pl_count
contains the serial number of this event.
Field
+.Va pl_tsc
+carries the raw CPU Time Stamp Counter (TSC) value recorded at the time
+of the event.
+This is not a wall-clock time; to convert to nanoseconds divide the TSC
+delta between two events by the TSC frequency
+.Pq Va pl_u.pl_i.pl_tsc_freq
+reported in the
+.Dv PMCLOG_TYPE_INITIALIZE
+record.
+The legacy
.Va pl_ts
-contains a timestamp with the system time when the event occurred.
+member aliases the same storage for ABI compatibility, but its contents
+no longer represent a wall-clock timestamp.
+.Pp
+Note that TSC-based timestamps and
+.Va pl_u.pl_i.pl_tsc_freq
+are only meaningful on x86 architectures
+.Pq amd64 and i386 .
+On all other architectures
+.Pq including arm64 and powerpc ,
+.Va pl_tsc
+and
+.Va pl_u.pl_i.pl_tsc_freq
+are set to zero.
Field
.Va pl_type
denotes the kind of the event returned in argument
diff --git a/lib/libpmc/pmclog.c b/lib/libpmc/pmclog.c
index 22ff50b10ee0..c3587af46c7b 100644
--- a/lib/libpmc/pmclog.c
+++ b/lib/libpmc/pmclog.c
@@ -287,8 +287,8 @@ pmclog_get_event(void *cookie, char **data, ssize_t *len,
return -1;
}
- /* copy out the time stamp */
- ev->pl_ts.tv_sec = ph->pl_tsc;
+ /* copy out the TSC from the event header */
+ ev->pl_tsc = ph->pl_tsc;
le += sizeof(*ph)/4;
evlen = PMCLOG_HEADER_TO_LENGTH(h);
diff --git a/lib/libpmc/pmclog.h b/lib/libpmc/pmclog.h
index 72e73e3928d2..a79d33529890 100644
--- a/lib/libpmc/pmclog.h
+++ b/lib/libpmc/pmclog.h
@@ -169,7 +169,10 @@ struct pmclog_ev {
enum pmclog_state pl_state; /* state after 'get_event()' */
off_t pl_offset; /* byte offset in stream */
size_t pl_count; /* count of records so far */
- struct timespec pl_ts; /* log entry timestamp */
+ union {
+ uint64_t pl_tsc; /* TSC timestamp */
+ struct timespec pl_ts; /* log entry timestamp (legacy) */
+ };
enum pmclog_type pl_type; /* type of log entry */
void *pl_data;
int pl_len;
@@ -229,4 +232,3 @@ void pmclog_close(void *_cookie);
__END_DECLS
#endif
-
diff --git a/lib/libsecureboot/h/verify_file.h b/lib/libsecureboot/h/verify_file.h
index f918ed6d0e38..19bef24b1dee 100644
--- a/lib/libsecureboot/h/verify_file.h
+++ b/lib/libsecureboot/h/verify_file.h
@@ -51,6 +51,7 @@ int ve_status_get(int);
int load_manifest(const char *, const char *, const char *, struct stat *);
int pass_manifest(const char *, const char *);
int pass_manifest_export_envs(void);
+int severity_guess(const char *);
void verify_report(const char *, int, int, struct stat *);
int verify_file(int, const char *, off_t, int, const char *);
void verify_pcr_export(void);
@@ -59,9 +60,9 @@ int is_verified(struct stat *);
void add_verify_status(struct stat *, int);
struct vectx;
-struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *, const char *);
+struct vectx* vectx_open(int, const char *, int, off_t, struct stat *, int *, const char *);
ssize_t vectx_read(struct vectx *, void *, size_t);
off_t vectx_lseek(struct vectx *, off_t, int);
-int vectx_close(struct vectx *, int, const char *);
+int vectx_close(struct vectx *, const char *);
#endif /* _VERIFY_FILE_H_ */
diff --git a/lib/libsecureboot/tests/tvo.c b/lib/libsecureboot/tests/tvo.c
index 7851e79c5a2a..407fcbefd6db 100644
--- a/lib/libsecureboot/tests/tvo.c
+++ b/lib/libsecureboot/tests/tvo.c
@@ -170,8 +170,8 @@ main(int argc, char *argv[])
fstat(fd, &st);
lseek(fd, 0, SEEK_SET);
off = st.st_size % 512;
- vp = vectx_open(fd, argv[optind], off,
- &st, &error, __func__);
+ vp = vectx_open(fd, argv[optind], VE_GUESS,
+ off, &st, &error, __func__);
if (!vp) {
printf("vectx_open(%s) failed: %d %s\n",
argv[optind], error,
@@ -190,7 +190,7 @@ main(int argc, char *argv[])
off = vectx_lseek(vp, 0, SEEK_END);
/* repeating that should be harmless */
off = vectx_lseek(vp, 0, SEEK_END);
- error = vectx_close(vp, VE_MUST, __func__);
+ error = vectx_close(vp, __func__);
if (error) {
printf("vectx_close(%s) == %d %s\n",
argv[optind], error,
diff --git a/lib/libsecureboot/vectx.c b/lib/libsecureboot/vectx.c
index 2d56830cd81d..4b42293a0d93 100644
--- a/lib/libsecureboot/vectx.c
+++ b/lib/libsecureboot/vectx.c
@@ -60,6 +60,7 @@ struct vectx {
int vec_fd; /* file descriptor */
int vec_status; /* verification status */
int vec_closing; /* we are closing */
+ int vec_severity; /* usually VE_MUST */
};
@@ -93,7 +94,8 @@ struct vectx {
* NULL is only returned for non-files or out-of-memory.
*/
struct vectx *
-vectx_open(int fd, const char *path, off_t off, struct stat *stp,
+vectx_open(int fd, const char *path, int severity,
+ off_t off, struct stat *stp,
int *error, const char *caller)
{
struct vectx *ctx;
@@ -106,14 +108,19 @@ vectx_open(int fd, const char *path, off_t off, struct stat *stp,
stp = &st;
rc = verify_prep(fd, path, off, stp, __func__);
+ if (severity == VE_GUESS)
+ severity = severity_guess(path);
DEBUG_PRINTF(2,
- ("vectx_open: caller=%s,fd=%d,name='%s',prep_rc=%d\n",
- caller, fd, path, rc));
+ ("vectx_open: caller=%s,fd=%d,name='%s',prep_rc=%d,severity=%d\n",
+ caller, fd, path, rc, severity));
switch (rc) {
case VE_FINGERPRINT_NONE:
case VE_FINGERPRINT_UNKNOWN:
+ if (severity < VE_MUST)
+ break;
+ /* FALLTHROUGH */
case VE_FINGERPRINT_WRONG:
*error = rc;
return (NULL);
@@ -127,19 +134,24 @@ vectx_open(int fd, const char *path, off_t off, struct stat *stp,
ctx->vec_off = 0;
ctx->vec_hashed = 0;
ctx->vec_want = NULL;
+ ctx->vec_severity = severity;
ctx->vec_status = 0;
ctx->vec_hashsz = hashsz = 0;
ctx->vec_closing = 0;
- if (rc == 0) {
+ if (rc == VE_UNVERIFIED_OK) {
/* we are not verifying this */
*error = 0;
return (ctx);
}
cp = fingerprint_info_lookup(fd, path);
if (!cp) {
- ctx->vec_status = VE_FINGERPRINT_NONE;
- ve_error_set("%s: no entry", path);
+ if (severity < VE_MUST)
+ ctx->vec_status = VE_UNVERIFIED_OK;
+ else {
+ ctx->vec_status = VE_FINGERPRINT_NONE;
+ ve_error_set("%s: no entry", path);
+ }
} else {
if (strncmp(cp, "no_hash", 7) == 0) {
ctx->vec_status = VE_FINGERPRINT_IGNORE;
@@ -167,8 +179,12 @@ vectx_open(int fd, const char *path, off_t off, struct stat *stp,
cp += 7;
#endif
} else {
- ctx->vec_status = VE_FINGERPRINT_UNKNOWN;
- ve_error_set("%s: no supported fingerprint", path);
+ if (severity < VE_MUST)
+ ctx->vec_status = VE_UNVERIFIED_OK;
+ else {
+ ctx->vec_status = VE_FINGERPRINT_UNKNOWN;
+ ve_error_set("%s: no supported fingerprint", path);
+ }
}
}
*error = ctx->vec_status;
@@ -183,9 +199,9 @@ vectx_open(int fd, const char *path, off_t off, struct stat *stp,
}
}
DEBUG_PRINTF(2,
- ("vectx_open: caller=%s,name='%s',hashsz=%lu,status=%d\n",
+ ("vectx_open: caller=%s,name='%s',hashsz=%lu,severity=%d,status=%d\n",
caller, path, (unsigned long)ctx->vec_hashsz,
- ctx->vec_status));
+ severity, ctx->vec_status));
return (ctx);
enomem: /* unlikely */
@@ -379,7 +395,7 @@ vectx_lseek(struct vectx *ctx, off_t off, int whence)
* @return 0 or an error.
*/
int
-vectx_close(struct vectx *ctx, int severity, const char *caller)
+vectx_close(struct vectx *ctx, const char *caller)
{
int rc;
@@ -393,7 +409,7 @@ vectx_close(struct vectx *ctx, int severity, const char *caller)
* these tend to be processed in a more deterministic
* order, which makes our pseudo pcr more useful.
*/
- ve_pcr_updating_set((severity == VE_MUST));
+ ve_pcr_updating_set((ctx->vec_severity == VE_MUST));
#endif
/* make sure we have hashed it all */
vectx_lseek(ctx, 0, SEEK_END);
@@ -401,13 +417,13 @@ vectx_close(struct vectx *ctx, int severity, const char *caller)
ctx->vec_path, ctx->vec_want, ctx->vec_hashsz);
}
DEBUG_PRINTF(2,
- ("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n",
- caller,ctx->vec_path, rc, severity));
- verify_report(ctx->vec_path, severity, rc, NULL);
+ ("vectx_close: caller=%s,name='%s',severity=%d,rc=%d\n",
+ caller,ctx->vec_path, ctx->vec_severity, rc));
+ verify_report(ctx->vec_path, ctx->vec_severity, rc, NULL);
if (rc == VE_FINGERPRINT_WRONG) {
#if !defined(UNIT_TEST) && !defined(DEBUG_VECTX)
/* we are generally called with VE_MUST */
- if (severity > VE_WANT)
+ if (ctx->vec_severity > VE_WANT)
panic("cannot continue");
#endif
}
diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c
index ee263dafe774..b1aad36672d0 100644
--- a/lib/libsecureboot/verify_file.c
+++ b/lib/libsecureboot/verify_file.c
@@ -271,7 +271,7 @@ find_manifest(const char *name)
# define ACCEPT_NO_FP_DEFAULT VE_MUST
#endif
-static int
+int
severity_guess(const char *filename)
{
const char *cp;
@@ -285,6 +285,7 @@ severity_guess(const char *filename)
*/
if ((cp = strrchr(filename, '.'))) {
if (strcmp(cp, ".cookie") == 0 ||
+ strcmp(cp, ".dof") == 0 ||
strcmp(cp, ".hints") == 0 ||
strcmp(cp, ".order") == 0 ||
strcmp(cp, ".tgz") == 0)
diff --git a/lib/libsys/fork.2 b/lib/libsys/fork.2
index e59b208a9ff5..89a5631d7daa 100644
--- a/lib/libsys/fork.2
+++ b/lib/libsys/fork.2
@@ -138,6 +138,7 @@ services (
or
.Xr rtld 1 )
are available in the child if forked from multi-threaded parent.
+.Pp
In particular, if using dynamic linking, all dynamic symbols used by the
child after
.Fn _Fork
@@ -151,6 +152,7 @@ option to the static linker
or by using each symbol before the
.Fn _Fork
call to force the binding.
+Either of the methods subtly changes the ABI of the resulting binary.
.Sh RETURN VALUES
Upon successful completion,
.Fn fork
diff --git a/lib/libsys/ntp_adjtime.2 b/lib/libsys/ntp_adjtime.2
index 5be5194a9c1d..ed43fb79a9f1 100644
--- a/lib/libsys/ntp_adjtime.2
+++ b/lib/libsys/ntp_adjtime.2
@@ -27,13 +27,13 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 13, 2005
+.Dd March 22, 2026
.Dt NTP_ADJTIME 2
.Os
.Sh NAME
.Nm ntp_adjtime ,
.Nm ntp_gettime
-.Nd Network Time Protocol (NTP) daemon interface system calls
+.Nd Network Time Protocol daemon (ntpd) interface system calls
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -59,7 +59,7 @@ The time offset and related variables which are set by
are used by
.Fn hardclock
to adjust the phase and frequency of the phase- or frequency-lock loop
-(PLL resp. FLL) which controls the system clock.
+(PLL resp\&. FLL) which controls the system clock.
.Pp
The
.Fn ntp_gettime
diff --git a/lib/libsys/shm_open.2 b/lib/libsys/shm_open.2
index c3196d966e6b..58597a341b9e 100644
--- a/lib/libsys/shm_open.2
+++ b/lib/libsys/shm_open.2
@@ -26,7 +26,7 @@
.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 4, 2025
+.Dd March 26, 2025
.Dt SHM_OPEN 2
.Os
.Sh NAME
@@ -343,7 +343,25 @@ Allow adding seals to the resulting file descriptor using the
.Xr fcntl 2
command.
.It Dv MFD_HUGETLB
-This flag is currently unsupported.
+Create a memfd backed by a
+.Dq largepage
+object.
+One of the
+.Dv MFD_HUGE_*
+flags defined in
+.In sys/mman.h
+may be included to specify a fixed size.
+If a specific size is not requested, the smallest supported large page size is
+selected.
+.Pp
+The behavior documented above for the
+.Fn shm_create_largepage
+.Fa psind
+argument also applies to largepage objects created by
+.Fn memfd_create ,
+and the
+.Dv SHM_LARGEPAGE_ALLOC_DEFAULT
+policy will always be used.
.El
.Sh RETURN VALUES
If successful,
@@ -458,17 +476,22 @@ argument was too long.
.Pp
An invalid or unsupported flag was included in
.Fa flags .
+.It Bq Er EINVAL
+A hugetlb mapping was requested, but
+.Dv MFD_HUGETLB
+was not specified in
+.Fa flags .
.It Bq Er EMFILE
The process has already reached its limit for open file descriptors.
.It Bq Er ENFILE
The system file table is full.
.It Bq Er ENOSYS
-In
-.Fa memfd_create ,
.Dv MFD_HUGETLB
was specified in
.Fa flags ,
and this system does not support forced hugetlb mappings.
+.It Bq Er EOPNOTSUPP
+This system does not support the requested hugetlb page size.
.El
.Pp
.Fn shm_open
diff --git a/lib/libsys/x86/pkru.3 b/lib/libsys/x86/pkru.3
index 95bc66c979ac..75580953e6ed 100644
--- a/lib/libsys/x86/pkru.3
+++ b/lib/libsys/x86/pkru.3
@@ -71,17 +71,17 @@ Only one key may apply to a given range at a time.
The default protection key index is zero, it is used even if no key
was explicitly assigned to the address, or if the key was removed.
.Pp
-The protection prevents the system from accessing user addresses as well
-as the user applications.
-When a system call was unable to read or write user memory due to key
-protection, it returns the
-.Er EFAULT
-error code.
-Note that some side effects may have occurred if this error is reported.
+If the user application attempts a memory access which is prohibited by the
+PKRU register, the offending thread receives a synchronous
+.Dv SIGSEGV
+signal with
+.Va si_code
+set to
+.Dv SEGV_PKUERR .
+PKRU protections might prevent the kernel from accessing protected
+user addresses when handling system calls, but this is not guaranteed and
+must not be relied upon.
.Pp
-Protection keys require that the system uses 4-level paging
-(also called long mode),
-which means that it is only available on amd64 system.
Both 64-bit and 32-bit applications can use protection keys.
More information about the hardware feature is provided in the IA32 Software
Developer's Manual published by Intel Corp.
diff --git a/lib/libthr/libthr.3 b/lib/libthr/libthr.3
index b84176abcd32..5d9c5ec6706b 100644
--- a/lib/libthr/libthr.3
+++ b/lib/libthr/libthr.3
@@ -52,6 +52,12 @@ The library is tightly integrated with the run-time link editor
and
.Lb libc ;
all three components must be built from the same source tree.
+Together, they constitute the base C runtime environment of
+.Fx ,
+running on top of the
+.Fx
+kernel.
+.Pp
Mixing
.Li libc
and
@@ -263,6 +269,25 @@ the critical section.
This should be taken into account when interpreting
.Xr ktrace 1
logs.
+.Pp
+The
+.Nm
+library uses the
+.Va SIGTHR
+signal for internal operations, in particular,
+for cancellation requests.
+This signal's masking and disposition is controlled by the library,
+and user programs should not try to modify them.
+The library interposes functions controlling signals to prevent
+inadvertent modifications and to guard portable code against
+exposure to
+.Va SIGTHR .
+.Pp
+Note: similarly, the
+.Va SIGLIBRT
+signal is reserved for use by
+.Lb librt ,
+and should be not modified by users.
.Sh PROCESS-SHARED SYNCHRONIZATION OBJECTS
In the
.Li libthr
diff --git a/lib/libzstd/Makefile b/lib/libzstd/Makefile
index 4a1557a14517..82e9d2a5b243 100644
--- a/lib/libzstd/Makefile
+++ b/lib/libzstd/Makefile
@@ -15,6 +15,7 @@ SRCS= entropy_common.c \
zstd_compress_literals.c \
zstd_compress_sequences.c \
zstd_compress_superblock.c \
+ zstd_preSplit.c \
zstdmt_compress.c \
huf_decompress.c \
zstd_ddict.c \
@@ -54,6 +55,9 @@ ZSTDDIR= ${SRCTOP}/sys/contrib/zstd
.include <bsd.compiler.mk>
+# These symbols are needed by dll-linked CLI zstd(1).
+CFLAGS.pool.c+= -fvisibility=default
+
CFLAGS.huf_decompress.c+= ${NO_WBITWISE_INSTEAD_OF_LOGICAL}
# https://github.com/facebook/zstd/commit/812e8f2a [zstd 1.4.1]
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
index 5112337f6297..d61f4e9a1659 100644
--- a/lib/msun/Makefile
+++ b/lib/msun/Makefile
@@ -76,7 +76,9 @@ COMMON_SRCS= b_tgamma.c \
s_finite.c s_finitef.c \
s_floor.c s_floorf.c s_fma.c s_fmaf.c \
s_fmax.c s_fmaxf.c s_fmaximum.c s_fmaximumf.c \
+ s_fmaximum_mag.c s_fmaximum_magf.c s_fmaximum_num.c s_fmaximum_numf.c \
s_fmin.c s_fminf.c s_fminimum.c s_fminimumf.c \
+ s_fminimum_mag.c s_fminimum_magf.c s_fminimum_num.c s_fminimum_numf.c \
s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \
s_ilogbl.c s_isfinite.c s_isnan.c s_isnormal.c \
s_llrint.c s_llrintf.c s_llround.c s_llroundf.c s_llroundl.c \
@@ -115,6 +117,7 @@ LIBC_ARCH=${MACHINE_CPUARCH}
CFLAGS+= -I${.CURDIR}/src -I${LIBC_SRCTOP}/include \
-I${LIBC_SRCTOP}/${LIBC_ARCH}
SYM_MAPS+= ${.CURDIR}/Symbol.map
+SYM_MAPS+= ${.CURDIR}/${ARCH_SUBDIR}/Symbol.map
VERSION_DEF= ${LIBC_SRCTOP}/Versions.def
SYMBOL_MAPS= ${SYM_MAPS}
@@ -132,7 +135,8 @@ COMMON_SRCS+= b_tgammal.c catrigl.c \
s_asinhl.c s_atanl.c s_cbrtl.c s_ceill.c s_cexpl.c \
s_clogl.c s_cosl.c s_cospil.c s_cprojl.c \
s_csqrtl.c s_erfl.c s_exp2l.c s_expl.c s_floorl.c s_fmal.c \
- s_fmaxl.c s_fmaximuml.c s_fminl.c s_fminimuml.c \
+ s_fmaxl.c s_fmaximuml.c s_fmaximum_magl.c s_fmaximum_numl.c \
+ s_fminl.c s_fminimuml.c s_fminimum_magl.c s_fminimum_numl.c \
s_frexpl.c s_logbl.c s_logl.c s_nanl.c \
s_nextafterl.c s_nexttoward.c s_remquol.c s_rintl.c s_roundl.c \
s_scalbnl.c s_sinl.c s_sincosl.c s_sinpil.c \
@@ -178,7 +182,8 @@ MAN= acos.3 acosh.3 asin.3 asinh.3 atan.3 atan2.3 atanh.3 \
exp.3 fabs.3 fdim.3 \
feclearexcept.3 feenableexcept.3 fegetenv.3 \
fegetround.3 fenv.3 floor.3 fma.3 \
- fmax.3 fmaximum.3 fmod.3 hypot.3 ieee.3 ieee_test.3 ilogb.3 j0.3 \
+ fmax.3 fmaximum.3 fmaximum_mag.3 fmaximum_num.3 fmod.3 \
+ hypot.3 ieee.3 ieee_test.3 ilogb.3 j0.3 \
lgamma.3 log.3 lrint.3 lround.3 math.3 nan.3 \
nextafter.3 remainder.3 rint.3 \
round.3 scalbn.3 signbit.3 sin.3 sincos.3 \
@@ -231,9 +236,15 @@ MLINKS+=floor.3 floorf.3 floor.3 floorl.3
MLINKS+=fma.3 fmaf.3 fma.3 fmal.3
MLINKS+=fmax.3 fmaxf.3 fmax.3 fmaxl.3 \
fmax.3 fmin.3 fmax.3 fminf.3 fmax.3 fminl.3
-MLINKS+=fmaximum.3 fmaximuml.3 fmaximum.3 fmaximumf.3 \
+MLINKS+=fmaximum.3 fmaximumf.3 fmaximum.3 fmaximuml.3 \
fmaximum.3 fminimum.3 fmaximum.3 fminimumf.3 \
fmaximum.3 fminimuml.3
+MLINKS+=fmaximum_mag.3 fmaximum_magf.3 fmaximum_mag.3 fmaximum_magl.3 \
+ fmaximum_mag.3 fminimum_mag.3 fmaximum_mag.3 fminimum_magf.3 \
+ fmaximum_mag.3 fminimum_magl.3
+MLINKS+=fmaximum_num.3 fmaximum_numf.3 fmaximum_num.3 fmaximum_numl.3 \
+ fmaximum_num.3 fminimum_num.3 fmaximum_num.3 fminimum_numf.3 \
+ fmaximum_num.3 fminimum_numl.3
MLINKS+=fmod.3 fmodf.3 fmod.3 fmodl.3
MLINKS+=hypot.3 cabs.3 hypot.3 cabsf.3 hypot.3 cabsl.3 \
hypot.3 hypotf.3 hypot.3 hypotl.3
diff --git a/lib/msun/Symbol.map b/lib/msun/Symbol.map
index 932cc000fe52..35addfcee3d5 100644
--- a/lib/msun/Symbol.map
+++ b/lib/msun/Symbol.map
@@ -326,4 +326,16 @@ FBSD_1.9 {
fminimum;
fminimumf;
fminimuml;
+ fmaximum_mag;
+ fmaximum_magf;
+ fmaximum_magl;
+ fminimum_mag;
+ fminimum_magf;
+ fminimum_magl;
+ fmaximum_num;
+ fmaximum_numf;
+ fmaximum_numl;
+ fminimum_num;
+ fminimum_numf;
+ fminimum_numl;
};
diff --git a/lib/msun/aarch64/Symbol.map b/lib/msun/aarch64/Symbol.map
new file mode 100644
index 000000000000..b468c814ff06
--- /dev/null
+++ b/lib/msun/aarch64/Symbol.map
@@ -0,0 +1,10 @@
+FBSD_1.9 {
+ fesetexceptflag;
+ feraiseexcept;
+ fegetenv;
+ feholdexcept;
+ feupdateenv;
+ feenableexcept;
+ fedisableexcept;
+ fegetexcept;
+};
diff --git a/lib/msun/aarch64/fenv.c b/lib/msun/aarch64/fenv.c
index a428a9d8a271..3d7e467880c7 100644
--- a/lib/msun/aarch64/fenv.c
+++ b/lib/msun/aarch64/fenv.c
@@ -98,3 +98,21 @@ int
{
return (__feupdateenv_int(envp));
}
+
+int
+(feenableexcept)(int mask)
+{
+ return (__feenableexcept_int(mask));
+}
+
+int
+(fedisableexcept)(int mask)
+{
+ return (__fedisableexcept_int(mask));
+}
+
+int
+(fegetexcept)(void)
+{
+ return (__fegetexcept_int());
+}
diff --git a/lib/msun/aarch64/fenv.h b/lib/msun/aarch64/fenv.h
index 32a03ee1eb49..5d47940cf9eb 100644
--- a/lib/msun/aarch64/fenv.h
+++ b/lib/msun/aarch64/fenv.h
@@ -92,6 +92,9 @@ int fegetenv(fenv_t *);
int feholdexcept(fenv_t *);
int fesetenv(const fenv_t *);
int feupdateenv(const fenv_t *);
+int feenableexcept(int);
+int fedisableexcept(int);
+int fegetexcept(void);
#define feclearexcept(a) __feclearexcept_int(a)
#define fegetexceptflag(e, a) __fegetexceptflag_int(e, a)
@@ -104,6 +107,9 @@ int feupdateenv(const fenv_t *);
#define feholdexcept(e) __feholdexcept_int(e)
#define fesetenv(e) __fesetenv_int(e)
#define feupdateenv(e) __feupdateenv_int(e)
+#define feenableexcept(a) __feenableexcept_int(a)
+#define fedisableexcept(a) __fedisableexcept_int(a)
+#define fegetexcept() __fegetexcept_int()
__fenv_static inline int
__feclearexcept_int(int __excepts)
@@ -233,10 +239,8 @@ __feupdateenv_int(const fenv_t *__envp)
#if __BSD_VISIBLE
-/* We currently provide no external definitions of the functions below. */
-
static inline int
-feenableexcept(int __mask)
+__feenableexcept_int(int __mask)
{
fenv_t __old_r, __new_r;
@@ -247,7 +251,7 @@ feenableexcept(int __mask)
}
static inline int
-fedisableexcept(int __mask)
+__fedisableexcept_int(int __mask)
{
fenv_t __old_r, __new_r;
@@ -258,7 +262,7 @@ fedisableexcept(int __mask)
}
static inline int
-fegetexcept(void)
+__fegetexcept_int(void)
{
fenv_t __r;
diff --git a/lib/msun/amd64/Makefile.inc b/lib/msun/amd64/Makefile.inc
index dcdc2495d690..f1e6aef552ca 100644
--- a/lib/msun/amd64/Makefile.inc
+++ b/lib/msun/amd64/Makefile.inc
@@ -6,4 +6,3 @@ ARCH_SRCS = e_fmod.S e_fmodf.S e_fmodl.S \
s_remquo.S s_remquof.S s_remquol.S \
s_rintl.S s_scalbn.S s_scalbnf.S s_scalbnl.S
LDBL_PREC = 64
-SYM_MAPS += ${.CURDIR}/amd64/Symbol.map
diff --git a/lib/msun/arm/Makefile.inc b/lib/msun/arm/Makefile.inc
index 6e3ddb351dd3..e155f1a2cae4 100644
--- a/lib/msun/arm/Makefile.inc
+++ b/lib/msun/arm/Makefile.inc
@@ -1,5 +1,4 @@
LDBL_PREC = 53
-SYM_MAPS += ${.CURDIR}/arm/Symbol.map
.if defined(CPUTYPE) && ${CPUTYPE:M*soft*} != ""
ARCH_SRCS = fenv-softfp.c fenv-vfp.c
diff --git a/lib/msun/i387/Makefile.inc b/lib/msun/i387/Makefile.inc
index 73feb52de6a2..f70c6b1bb569 100644
--- a/lib/msun/i387/Makefile.inc
+++ b/lib/msun/i387/Makefile.inc
@@ -17,4 +17,3 @@ ARCH_SRCS+= e_fmodl.S \
s_logbl.S s_lrintl.S s_remquol.S s_rintl.S s_scalbnl.S s_truncl.S
LDBL_PREC = 64 # XXX 64-bit format, but truncated to 53 bits
-SYM_MAPS += ${.CURDIR}/i387/Symbol.map
diff --git a/lib/msun/man/fmax.3 b/lib/msun/man/fmax.3
index 873a19375ce5..3b167a0b6f8d 100644
--- a/lib/msun/man/fmax.3
+++ b/lib/msun/man/fmax.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 6, 2026
+.Dd April 11, 2026
.Dt FMAX 3
.Os
.Sh NAME
@@ -93,6 +93,13 @@ as being larger than
.Li -0.0 .
This behavior is not specified by the C standard, is not portable,
and may not occur in light of compiler optimizations.
+Applications requiring specific handling of signed zeroes or
+.No \*(Na
+values are recommended to use
+.Xr fmaximum_num 3
+and
+.Xr fminimum_num 3
+instead, which have strictly defined behavior for these cases.
.Sh HISTORY
These routines first appeared in
.Fx 5.3 .
diff --git a/lib/msun/man/fmaximum.3 b/lib/msun/man/fmaximum.3
index bd301163a034..ef26c12268c0 100644
--- a/lib/msun/man/fmaximum.3
+++ b/lib/msun/man/fmaximum.3
@@ -83,9 +83,9 @@ or
is an \*(Na, then the result is an \*(Na.
These routines do not raise any floating-point exceptions.
.Sh SEE ALSO
-.Xr fabs 3 ,
-.Xr fdim 3 ,
.Xr fmax 3 ,
+.Xr fmaximum_num 3 ,
+.Xr fmaximum_mag 3 ,
.Xr math 3
.Sh STANDARDS
The
diff --git a/lib/msun/man/fmaximum_mag.3 b/lib/msun/man/fmaximum_mag.3
new file mode 100644
index 000000000000..f5e4c39f96ef
--- /dev/null
+++ b/lib/msun/man/fmaximum_mag.3
@@ -0,0 +1,102 @@
+.\" Copyright (c) 2004 David Schultz <das@FreeBSD.org>
+.\" Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 3, 2026
+.Dt FMAXIMUM_MAG 3
+.Os
+.Sh NAME
+.Nm fmaximum_mag ,
+.Nm fmaximum_magf ,
+.Nm fmaximum_magl ,
+.Nm fminimum_mag ,
+.Nm fminimum_magf ,
+.Nm fminimum_magl
+.Nd floating-point maximum and minimum magnitude functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fmaximum_mag "double x" "double y"
+.Ft float
+.Fn fmaximum_magf "float x" "float y"
+.Ft "long double"
+.Fn fmaximum_magl "long double x" "long double y"
+.Ft double
+.Fn fminimum_mag "double x" "double y"
+.Ft float
+.Fn fminimum_magf "float x" "float y"
+.Ft "long double"
+.Fn fminimum_magl "long double x" "long double y"
+.Sh DESCRIPTION
+The
+.Fn fmaximum_mag ,
+.Fn fmaximum_magf ,
+and
+.Fn fmaximum_magl
+functions determine the larger of the absolute values of
+.Fa x
+and
+.Fa y ,
+and return the argument with the larger absolute value.
+If the absolute values are equal, the behavior is equivalent to calling the corresponding
+.Fn fmaximum
+function on the arguments.
+.Pp
+Likewise, the
+.Fn fminimum_mag ,
+.Fn fminimum_magf ,
+and
+.Fn fminimum_magl
+functions determine the smaller of the absolute values of
+.Fa x
+and
+.Fa y ,
+and return the argument with the smaller absolute value.
+If the absolute values are equal, the behavior is equivalent to calling the corresponding
+.Fn fminimum
+function on the arguments.
+.Pp
+If either argument is an \*(Na, then the result is an \*(Na.
+These routines do not raise any floating-point exceptions.
+.Sh SEE ALSO
+.Xr fmax 3 ,
+.Xr fmaximum 3 ,
+.Xr fmaximum_num 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fmaximum_mag ,
+.Fn fmaximum_magf ,
+.Fn fmaximum_magl ,
+.Fn fminimum_mag ,
+.Fn fminimum_magf ,
+and
+.Fn fminimum_magl
+functions conform to
+.St -isoC-2023 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 16.0 .
diff --git a/lib/msun/man/fmaximum_num.3 b/lib/msun/man/fmaximum_num.3
new file mode 100644
index 000000000000..33fa759f0173
--- /dev/null
+++ b/lib/msun/man/fmaximum_num.3
@@ -0,0 +1,113 @@
+.\" Copyright (c) 2004 David Schultz <das@FreeBSD.org>
+.\" Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 3, 2026
+.Dt FMAXIMUM_NUM 3
+.Os
+.Sh NAME
+.Nm fmaximum_num ,
+.Nm fmaximum_numf ,
+.Nm fmaximum_numl ,
+.Nm fminimum_num ,
+.Nm fminimum_numf ,
+.Nm fminimum_numl
+.Nd floating-point maximum and minimum number functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fmaximum_num "double x" "double y"
+.Ft float
+.Fn fmaximum_numf "float x" "float y"
+.Ft "long double"
+.Fn fmaximum_numl "long double x" "long double y"
+.Ft double
+.Fn fminimum_num "double x" "double y"
+.Ft float
+.Fn fminimum_numf "float x" "float y"
+.Ft "long double"
+.Fn fminimum_numl "long double x" "long double y"
+.Sh DESCRIPTION
+The
+.Fn fmaximum_num ,
+.Fn fmaximum_numf ,
+and
+.Fn fmaximum_numl
+functions determine the larger of
+.Fa x
+and
+.Fa y ,
+preferring a numeric value over an \*(Na.
+If one argument is a numeric value and the other is an \*(Na,
+the numeric value is returned.
+If both arguments are numeric, the larger value is returned.
+If both arguments are \*(Nas, a quiet \*(Na is returned.
+For the purpose of these functions, positive zero is considered
+greater than negative zero.
+.Pp
+Likewise, the
+.Fn fminimum_num ,
+.Fn fminimum_numf ,
+and
+.Fn fminimum_numl
+functions determine the smaller of
+.Fa x
+and
+.Fa y ,
+preferring a numeric value over an \*(Na.
+If one argument is a numeric value and the other is an \*(Na,
+the numeric value is returned.
+If both arguments are numeric, the smaller value is returned.
+If both arguments are \*(Nas, a quiet \*(Na is returned.
+For the purpose of these functions, negative zero is considered
+less than positive zero.
+.Pp
+Unlike with the
+.Xr fmaximum 3
+and
+.Xr fmaximum_mag 3
+families of functions, if either argument is a signaling \*(Na,
+an invalid exception is raised.
+Otherwise, these routines do not raise any floating-point exceptions.
+.Sh SEE ALSO
+.Xr fmax 3 ,
+.Xr fmaximum 3 ,
+.Xr fmaximum_mag 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fmaximum_num ,
+.Fn fmaximum_numf ,
+.Fn fmaximum_numl ,
+.Fn fminimum_num ,
+.Fn fminimum_numf ,
+and
+.Fn fminimum_numl
+functions conform to
+.St -isoC-2023 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 16.0 .
diff --git a/lib/msun/man/math.3 b/lib/msun/man/math.3
index 47353298bb54..f98c5e1a2a75 100644
--- a/lib/msun/man/math.3
+++ b/lib/msun/man/math.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 7, 2017
+.Dd April 11, 2026
.Dt MATH 3
.Os
.Sh NAME
@@ -115,8 +115,14 @@ scalbn adjust exponent
copysign copy sign bit
fabs absolute value
fdim positive difference
-fmax maximum function
-fmin minimum function
+fmax maximum function (legacy)
+fmaximum maximum function (prefers \*(Na)
+fmaximum_mag maximum magnitude (prefers \*(Na)
+fmaximum_num maximum function (avoids \*(Na)
+fmin minimum function (legacy)
+fminimum minimum function (prefers \*(Na)
+fminimum_mag minimum magnitude (prefers \*(Na)
+fminimum_num minimum function (avoids \*(Na)
signbit extract sign bit
.El
.Ss Not a Number Functions
diff --git a/lib/msun/powerpc/Makefile.inc b/lib/msun/powerpc/Makefile.inc
index 35747abb7087..2ae9bacdaab0 100644
--- a/lib/msun/powerpc/Makefile.inc
+++ b/lib/msun/powerpc/Makefile.inc
@@ -1,2 +1 @@
LDBL_PREC = 53
-SYM_MAPS += ${.CURDIR}/powerpc/Symbol.map
diff --git a/lib/msun/riscv/Makefile.inc b/lib/msun/riscv/Makefile.inc
index 6262cfd6981e..ee32db47286d 100644
--- a/lib/msun/riscv/Makefile.inc
+++ b/lib/msun/riscv/Makefile.inc
@@ -1,2 +1 @@
LDBL_PREC = 113
-SYM_MAPS += ${.CURDIR}/riscv/Symbol.map
diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h
index 103b82c1cdf8..853984953a91 100644
--- a/lib/msun/src/math.h
+++ b/lib/msun/src/math.h
@@ -526,6 +526,18 @@ long double fmaximuml(long double, long double);
double fminimum(double, double);
float fminimumf(float, float);
long double fminimuml(long double, long double);
+double fmaximum_mag(double, double);
+float fmaximum_magf(float, float);
+long double fmaximum_magl(long double, long double);
+double fminimum_mag(double, double);
+float fminimum_magf(float, float);
+long double fminimum_magl(long double, long double);
+double fmaximum_num(double, double);
+float fmaximum_numf(float, float);
+long double fmaximum_numl(long double, long double);
+double fminimum_num(double, double);
+float fminimum_numf(float, float);
+long double fminimum_numl(long double, long double);
#endif /* __ISO_C_VISIBLE >= 2023 */
__END_DECLS
diff --git a/lib/msun/src/s_fmaximum_mag.c b/lib/msun/src/s_fmaximum_mag.c
new file mode 100644
index 000000000000..1b1250f4c36e
--- /dev/null
+++ b/lib/msun/src/s_fmaximum_mag.c
@@ -0,0 +1,73 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMAXIMUM_MAG
+double
+fmaximum_mag(double x, double y)
+{
+ return (__builtin_fmaximum_mag(x, y));
+}
+#else
+double
+fmaximum_mag(double x, double y)
+{
+ union IEEEd2bits u[2];
+
+ u[0].d = x;
+ u[1].d = y;
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if ((u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0) ||
+ (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0))
+ return (NAN);
+
+ double ax = fabs(x);
+ double ay = fabs(y);
+
+ if (ay > ax)
+ return (y);
+ if (ax > ay)
+ return (x);
+
+ /* If magnitudes are equal, we break the tie with the sign */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].d);
+
+ return (x);
+}
+#endif
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fmaximum_mag, fmaximum_magl);
+#endif
+
diff --git a/lib/msun/src/s_fmaximum_magf.c b/lib/msun/src/s_fmaximum_magf.c
new file mode 100644
index 000000000000..6193b9184970
--- /dev/null
+++ b/lib/msun/src/s_fmaximum_magf.c
@@ -0,0 +1,68 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMAXIMUM_MAGF
+float
+fmaximum_magf(float x, float y)
+{
+ return (__builtin_fmaximum_magf(x, y));
+}
+#else
+float
+fmaximum_magf(float x, float y)
+{
+ union IEEEf2bits u[2];
+
+ u[0].f = x;
+ u[1].f = y;
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if ((u[0].bits.exp == 255 && u[0].bits.man != 0) ||
+ (u[1].bits.exp == 255 && u[1].bits.man != 0))
+ return (NAN);
+
+ float ax = fabsf(x);
+ float ay = fabsf(y);
+
+ if (ay > ax)
+ return (y);
+ if (ax > ay)
+ return (x);
+
+ /* If magnitudes are equal, we break the tie with the sign */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].f);
+
+ return (x);
+}
+#endif
+
diff --git a/lib/msun/src/s_fmaximum_magl.c b/lib/msun/src/s_fmaximum_magl.c
new file mode 100644
index 000000000000..f2426b050d33
--- /dev/null
+++ b/lib/msun/src/s_fmaximum_magl.c
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fmaximum_magl(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if ((u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0) ||
+ (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0))
+ return (NAN);
+
+ long double ax = fabsl(x);
+ long double ay = fabsl(y);
+
+ if (ay > ax)
+ return (y);
+ if (ax > ay)
+ return (x);
+
+ /* If magnitudes are equal, we break the tie with the sign */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[0].bits.sign ? y : x);
+
+ return (x);
+}
+
diff --git a/lib/msun/src/s_fmaximum_num.c b/lib/msun/src/s_fmaximum_num.c
new file mode 100644
index 000000000000..cf16c76f89b9
--- /dev/null
+++ b/lib/msun/src/s_fmaximum_num.c
@@ -0,0 +1,74 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <float.h>
+#include <math.h>
+#include <stdbool.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMAXIMUM_NUM
+double
+fmaximum_num(double x, double y)
+{
+ return (__builtin_fmaximum_num(x, y));
+}
+#else
+double
+fmaximum_num(double x, double y)
+{
+ union IEEEd2bits u[2];
+ bool nan_x, nan_y;
+
+ u[0].d = x;
+ u[1].d = y;
+
+ nan_x = u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0;
+ nan_y = u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0;
+
+ if (nan_x || nan_y) {
+ /* These ternary conditionals force (x+y), so that sNaN's raise exceptions */
+ if (nan_x && nan_y)
+ return (x + y);
+ if (nan_x)
+ return ((x + y) != 0.0 ? y : y);
+ return ((x + y) != 0.0 ? x : x);
+ }
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].d);
+
+ return (x > y ? x : y);
+}
+#endif
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fmaximum_num, fmaximum_numl);
+#endif
diff --git a/lib/msun/src/s_fmaximum_numf.c b/lib/msun/src/s_fmaximum_numf.c
new file mode 100644
index 000000000000..c30179e47f9e
--- /dev/null
+++ b/lib/msun/src/s_fmaximum_numf.c
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include <stdbool.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMAXIMUM_NUMF
+float
+fmaximum_numf(float x, float y)
+{
+ return (__builtin_fmaximum_numf(x, y));
+}
+#else
+float
+fmaximum_numf(float x, float y)
+{
+ union IEEEf2bits u[2];
+ bool nan_x, nan_y;
+
+ u[0].f = x;
+ u[1].f = y;
+
+ nan_x = u[0].bits.exp == 255 && u[0].bits.man != 0;
+ nan_y = u[1].bits.exp == 255 && u[1].bits.man != 0;
+
+ if (nan_x || nan_y) {
+ /* These ternary conditionals force (x+y), so that sNaN's raise exceptions */
+ if (nan_x && nan_y)
+ return (x + y);
+ if (nan_x)
+ return ((x + y) != 0.0 ? y : y);
+ return ((x + y) != 0.0 ? x : x);
+ }
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].f);
+
+ return (x > y ? x : y);
+}
+#endif
+
diff --git a/lib/msun/src/s_fmaximum_numl.c b/lib/msun/src/s_fmaximum_numl.c
new file mode 100644
index 000000000000..2291d01ca4f4
--- /dev/null
+++ b/lib/msun/src/s_fmaximum_numl.c
@@ -0,0 +1,63 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include <stdbool.h>
+
+#include "fpmath.h"
+
+long double
+fmaximum_numl(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+ bool nan_x, nan_y;
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ nan_x = u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0;
+ nan_y = u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0;
+
+ if (nan_x || nan_y) {
+ /* These ternary conditionals force (x+y), so that sNaN's raise exceptions */
+ if (nan_x && nan_y)
+ return (x + y);
+ if (nan_x)
+ return ((x + y) != 0.0 ? y : y);
+ return ((x + y) != 0.0 ? x : x);
+ }
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[0].bits.sign ? y : x);
+
+ return (x > y ? x : y);
+}
diff --git a/lib/msun/src/s_fminimum.c b/lib/msun/src/s_fminimum.c
index 64c81b560626..fa3fd17fe241 100644
--- a/lib/msun/src/s_fminimum.c
+++ b/lib/msun/src/s_fminimum.c
@@ -47,7 +47,7 @@ fminimum(double x, double y)
u[0].d = x;
u[1].d = y;
- /* Check for NaNs to avoid raising spurious exceptions. */
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0 ||
u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
return (NAN);
diff --git a/lib/msun/src/s_fminimum_mag.c b/lib/msun/src/s_fminimum_mag.c
new file mode 100644
index 000000000000..cd21fb948a8e
--- /dev/null
+++ b/lib/msun/src/s_fminimum_mag.c
@@ -0,0 +1,74 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMINIMUM_MAG
+double
+fminimum_mag(double x, double y)
+{
+ return (__builtin_fminimum_mag(x, y));
+}
+#else
+double
+fminimum_mag(double x, double y)
+{
+ union IEEEd2bits u[2];
+
+ u[0].d = x;
+ u[1].d = y;
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0 ||
+ u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (NAN);
+
+ double ax = fabs(x);
+ double ay = fabs(y);
+
+ if (ay < ax)
+ return (y);
+ if (ax < ay)
+ return (x);
+
+ /* If magnitudes are equal, we break the tie with the sign */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].d);
+
+ return (x);
+}
+#endif
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fminimum_mag, fminimum_magl);
+#endif
+
+
diff --git a/lib/msun/src/s_fminimum_magf.c b/lib/msun/src/s_fminimum_magf.c
new file mode 100644
index 000000000000..9c04859184ea
--- /dev/null
+++ b/lib/msun/src/s_fminimum_magf.c
@@ -0,0 +1,69 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMINIMUM_MAGF
+float
+fminimum_magf(float x, float y)
+{
+ return (__builtin_fminimum_magf(x, y));
+}
+#else
+float
+fminimum_magf(float x, float y)
+{
+ union IEEEf2bits u[2];
+
+ u[0].f = x;
+ u[1].f = y;
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if (u[0].bits.exp == 255 && u[0].bits.man != 0 ||
+ u[1].bits.exp == 255 && u[1].bits.man != 0)
+ return (NAN);
+
+ float ax = fabsf(x);
+ float ay = fabsf(y);
+
+ if (ay < ax)
+ return (y);
+ if (ax < ay)
+ return (x);
+
+ /* If magnitudes are equal, we break the tie with the sign */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].f);
+
+ return (x);
+}
+#endif
+
+
diff --git a/lib/msun/src/s_fminimum_magl.c b/lib/msun/src/s_fminimum_magl.c
new file mode 100644
index 000000000000..e6ab22afe7f0
--- /dev/null
+++ b/lib/msun/src/s_fminimum_magl.c
@@ -0,0 +1,63 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fminimum_magl(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0 ||
+ u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (NAN);
+
+ long double ax = fabsl(x);
+ long double ay = fabsl(y);
+
+ if (ay < ax)
+ return (y);
+ if (ax < ay)
+ return (x);
+
+ /* If magnitudes are equal, we break the tie with the sign */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[1].bits.sign ? y : x);
+
+ return (x);
+}
+
+
diff --git a/lib/msun/src/s_fminimum_num.c b/lib/msun/src/s_fminimum_num.c
new file mode 100644
index 000000000000..71b5f072c32d
--- /dev/null
+++ b/lib/msun/src/s_fminimum_num.c
@@ -0,0 +1,76 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <float.h>
+#include <math.h>
+#include <stdbool.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMINIMUM_NUM
+double
+fminimum_num(double x, double y)
+{
+ return (__builtin_fminimum_num(x, y));
+}
+#else
+double
+fminimum_num(double x, double y)
+{
+ union IEEEd2bits u[2];
+ bool nan_x, nan_y;
+
+ u[0].d = x;
+ u[1].d = y;
+
+ nan_x = u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0;
+ nan_y = u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0;
+
+ if (nan_x || nan_y) {
+ /* These ternary conditionals force (x+y), so that sNaN's raise exceptions */
+ if (nan_x && nan_y)
+ return (x + y);
+ if (nan_x)
+ return ((x + y) != 0.0 ? y : y);
+ return ((x + y) != 0.0 ? x : x);
+ }
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].d);
+
+ return (x < y ? x : y);
+}
+#endif
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fminimum_num, fminimum_numl);
+#endif
+
+
diff --git a/lib/msun/src/s_fminimum_numf.c b/lib/msun/src/s_fminimum_numf.c
new file mode 100644
index 000000000000..d5bab31ce403
--- /dev/null
+++ b/lib/msun/src/s_fminimum_numf.c
@@ -0,0 +1,71 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include <stdbool.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMINIMUM_NUMF
+float
+fminimum_numf(float x, float y)
+{
+ return (__builtin_fminimum_numf(x, y));
+}
+#else
+float
+fminimum_numf(float x, float y)
+{
+ union IEEEf2bits u[2];
+ bool nan_x, nan_y;
+
+ u[0].f = x;
+ u[1].f = y;
+
+ nan_x = u[0].bits.exp == 255 && u[0].bits.man != 0;
+ nan_y = u[1].bits.exp == 255 && u[1].bits.man != 0;
+
+ if (nan_x || nan_y) {
+ /* These ternary conditionals force (x+y), so that sNaN's raise exceptions */
+ if (nan_x && nan_y)
+ return (x + y);
+ if (nan_x)
+ return ((x + y) != 0.0 ? y : y);
+ return ((x + y) != 0.0 ? x : x);
+ }
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].f);
+
+ return (x < y ? x : y);
+}
+#endif
+
+
diff --git a/lib/msun/src/s_fminimum_numl.c b/lib/msun/src/s_fminimum_numl.c
new file mode 100644
index 000000000000..6b26d2218d42
--- /dev/null
+++ b/lib/msun/src/s_fminimum_numl.c
@@ -0,0 +1,65 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include <stdbool.h>
+
+#include "fpmath.h"
+
+long double
+fminimum_numl(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+ bool nan_x, nan_y;
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ nan_x = u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0;
+ nan_y = u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0;
+
+ if (nan_x || nan_y) {
+ /* These ternary conditionals force (x+y), so that sNaN's raise exceptions */
+ if (nan_x && nan_y)
+ return (x + y);
+ if (nan_x)
+ return ((x + y) != 0.0 ? y : y);
+ return ((x + y) != 0.0 ? x : x);
+ }
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[1].bits.sign ? y : x);
+
+ return (x < y ? x : y);
+}
+
+
diff --git a/lib/msun/src/s_fminimumf.c b/lib/msun/src/s_fminimumf.c
index d3978f576931..08ac3ca4c158 100644
--- a/lib/msun/src/s_fminimumf.c
+++ b/lib/msun/src/s_fminimumf.c
@@ -46,7 +46,7 @@ fminimumf(float x, float y)
u[0].f = x;
u[1].f = y;
- /* Check for NaNs to avoid raising spurious exceptions. */
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
if (u[0].bits.exp == 255 && u[0].bits.man != 0 ||
u[1].bits.exp == 255 && u[1].bits.man != 0)
return (NAN);
diff --git a/lib/msun/src/s_fminimuml.c b/lib/msun/src/s_fminimuml.c
index e2c5527ee319..1ef9078ee674 100644
--- a/lib/msun/src/s_fminimuml.c
+++ b/lib/msun/src/s_fminimuml.c
@@ -41,7 +41,7 @@ fminimuml(long double x, long double y)
u[1].e = y;
mask_nbit_l(u[1]);
- /* Check for NaNs to avoid raising spurious exceptions. */
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0 ||
u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
return (NAN);
diff --git a/lib/msun/tests/fmaximum_fminimum_test.c b/lib/msun/tests/fmaximum_fminimum_test.c
index 4641f80dfdad..4c8ec9a5b0e0 100644
--- a/lib/msun/tests/fmaximum_fminimum_test.c
+++ b/lib/msun/tests/fmaximum_fminimum_test.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2008 David Schultz <das@FreeBSD.org>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,7 +26,8 @@
*/
/*
- * Tests for fmaximum{,f,l}() and fminimum{,f,l}()
+ * Tests for fmaximum{,f,l}(), fminimum{,f,l}(), fmaximum_mag{,f,l},
+ * fminimum_mag{,f,l}, fmaximum_num{,f,l}, fminimum_num{,f,l}
*/
#include <sys/cdefs.h>
@@ -58,7 +60,7 @@ testall_r(long double big, long double small, int rmode)
{
long double expected_max, expected_min;
if (isnan(big) || isnan(small)) {
- expected_max = big + small;
+ expected_max = NAN;
expected_min = expected_max;
} else {
expected_max = big;
@@ -79,6 +81,55 @@ testall_r(long double big, long double small, int rmode)
TEST(fminimuml, long double, small, big, expected_min, rmode);
}
+static void
+testall_mag_r(long double big, long double small, int rmode) {
+ long double expected_max_mag, expected_min_mag;
+ if (isnan(big) || isnan(small)) {
+ expected_max_mag = NAN;
+ expected_min_mag = expected_max_mag;
+ } else {
+ if (fabsl(small) > fabsl(big)) {
+ expected_max_mag = small;
+ expected_min_mag = big;
+ } else {
+ expected_max_mag = big;
+ expected_min_mag = small;
+ }
+ }
+
+ TEST(fmaximum_magf, float, big, small, expected_max_mag, rmode);
+ TEST(fmaximum_magf, float, small, big, expected_max_mag, rmode);
+ TEST(fmaximum_mag, double, big, small, expected_max_mag, rmode);
+ TEST(fmaximum_mag, double, small, big, expected_max_mag, rmode);
+ TEST(fmaximum_magl, long double, big, small, expected_max_mag, rmode);
+ TEST(fmaximum_magl, long double, small, big, expected_max_mag, rmode);
+ TEST(fminimum_magf, float, big, small, expected_min_mag, rmode);
+ TEST(fminimum_magf, float, small, big, expected_min_mag, rmode);
+ TEST(fminimum_mag, double, big, small, expected_min_mag, rmode);
+ TEST(fminimum_mag, double, small, big, expected_min_mag, rmode);
+ TEST(fminimum_magl, long double, big, small, expected_min_mag, rmode);
+ TEST(fminimum_magl, long double, small, big, expected_min_mag, rmode);
+}
+
+static void
+testall_num_r(long double big, long double small, int rmode) {
+ long double expected_max_num = isnan(big) ? small : big;
+ long double expected_min_num = isnan(small) ? big : small;
+
+ TEST(fmaximum_numf, float, big, small, expected_max_num, rmode);
+ TEST(fmaximum_numf, float, small, big, expected_max_num, rmode);
+ TEST(fmaximum_num, double, big, small, expected_max_num, rmode);
+ TEST(fmaximum_num, double, small, big, expected_max_num, rmode);
+ TEST(fmaximum_numl, long double, big, small, expected_max_num, rmode);
+ TEST(fmaximum_numl, long double, small, big, expected_max_num, rmode);
+ TEST(fminimum_numf, float, big, small, expected_min_num, rmode);
+ TEST(fminimum_numf, float, small, big, expected_min_num, rmode);
+ TEST(fminimum_num, double, big, small, expected_min_num, rmode);
+ TEST(fminimum_num, double, small, big, expected_min_num, rmode);
+ TEST(fminimum_numl, long double, big, small, expected_min_num, rmode);
+ TEST(fminimum_numl, long double, small, big, expected_min_num, rmode);
+}
+
/*
* Test all the functions: fmaximumf, fmaximum, fmaximuml, fminimumf, fminimum, fminimuml
* in all rounding modes and with the arguments in different orders.
@@ -95,6 +146,8 @@ testall(long double big, long double small)
for (i = 0; i < 4; i++) {
fesetround(rmodes[i]);
testall_r(big, small, rmodes[i]);
+ testall_mag_r(big, small, rmodes[i]);
+ testall_num_r(big, small, rmodes[i]);
}
}
@@ -169,6 +222,24 @@ ATF_TC_BODY(test12, tc)
}
+ATF_TC_WITHOUT_HEAD(test13);
+ATF_TC_BODY(test13, tc)
+{
+ testall(2.0, -2.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test14);
+ATF_TC_BODY(test14, tc)
+{
+ testall(-0.0, -0.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test15);
+ATF_TC_BODY(test15, tc)
+{
+ testall(0.0, 0.0);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, test1);
@@ -183,6 +254,9 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, test10);
ATF_TP_ADD_TC(tp, test11);
ATF_TP_ADD_TC(tp, test12);
+ ATF_TP_ADD_TC(tp, test13);
+ ATF_TP_ADD_TC(tp, test14);
+ ATF_TP_ADD_TC(tp, test15);
return (atf_no_error());
}