diff options
Diffstat (limited to 'lib')
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()); } |
