diff --git a/.gitattributes b/.gitattributes --- a/.gitattributes +++ b/.gitattributes @@ -3,5 +3,3 @@ *.cpp diff=cpp *.hpp diff=cpp *.py diff=python -. svn-properties=svn:keywords=tools/build/options/WITHOUT_LOADER_ZFS -.clang-format svn-properties=svn:keywords=FreeBSD=%H diff --git a/LOCKS b/LOCKS --- a/LOCKS +++ b/LOCKS @@ -6,8 +6,6 @@ -------------------------------------- Special cases: -releng/* Requires Security Officer approval. -head/sys/dev/random Requires Security Officer approval. -head/sys/libkern/arc4random.c Requires Security Officer approval. -stable/*/sys/dev/random Requires Security Officer approval. -stable/*/sys/libkern/arc4random.c Requires Security Officer approval. +releng/* branches Requires Security Officer approval. +/sys/dev/random Requires Security Officer approval. +/sys/libkern/arc4random.c Requires Security Officer approval. diff --git a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,8 +1,8 @@ Please note that the content of this file is strictly advisory. No locks listed here are valid. The only strict review requirements -are granted by core. These are documented in head/LOCKS and enforced -by svnadmin/conf/approvers. +are granted by core. These are documented in LOCKS and enforced +by gitadm@. The source tree is a community effort. However, some folks go to the trouble of looking after particular areas of the tree. In return for diff --git a/RELNOTES b/RELNOTES --- a/RELNOTES +++ b/RELNOTES @@ -10,6 +10,12 @@ Changes to this file should not be MFCed. +7c5146da1286: + Mountd has been modified to use strunvis(3) to decode directory + names in exports(5) file(s). This allows special characters, + such as blanks, to be embedded in the directory name(s). + "vis -M" may be used to encode such directory name(s). + c5359e2af5ab: bhyve(8) has a new network backend, "slirp", which makes use of the libslirp package to provide a userspace network stack. This backend diff --git a/bin/cat/Makefile b/bin/cat/Makefile --- a/bin/cat/Makefile +++ b/bin/cat/Makefile @@ -20,7 +20,7 @@ #LIBADD+= cap_net #CFLAGS+=-DWITH_CASPER #.endif -# Depend on Makefile to rebiuld when WITH_CASPER changes +# Depend on Makefile to rebuild when WITH_CASPER changes cat.o: Makefile .include diff --git a/bin/df/df.1 b/bin/df/df.1 --- a/bin/df/df.1 +++ b/bin/df/df.1 @@ -120,7 +120,7 @@ Select locally-mounted file system for display. If used in combination with the .Fl t Ar type -option, file system types will be added or excluded acccording to the +option, file system types will be added or excluded according to the parameters of that option. .It Fl m Use 1048576 byte (1 Mebibyte) blocks rather than the default. diff --git a/bin/mv/mv.c b/bin/mv/mv.c --- a/bin/mv/mv.c +++ b/bin/mv/mv.c @@ -172,7 +172,7 @@ */ if (!fflg && !access(to, F_OK)) { - /* prompt only if source exist */ + /* prompt only if source exists */ if (lstat(from, &sb) == -1) { warn("%s", from); return (1); diff --git a/bin/pax/pax.c b/bin/pax/pax.c --- a/bin/pax/pax.c +++ b/bin/pax/pax.c @@ -69,7 +69,7 @@ int tflag; /* restore access time after read */ int uflag; /* ignore older modification time files */ int vflag; /* produce verbose output */ -int Dflag; /* same as uflag except inode change time */ +int Dflag; /* same as uflag except for inode change time */ int Hflag; /* follow command line symlinks (write only) */ int Lflag; /* follow symlinks when writing */ int Oflag; /* limit to single volume */ diff --git a/bin/sh/eval.c b/bin/sh/eval.c --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -899,7 +899,7 @@ * so we just delete the hash before and after * the command runs. Partly deleting like * changepatch() does doesn't seem worth the - * bookinging effort, since most such runs add + * booking effort, since most such runs add * directories in front of the new PATH. */ clearcmdentry(); diff --git a/bin/sh/mail.c b/bin/sh/mail.c --- a/bin/sh/mail.c +++ b/bin/sh/mail.c @@ -55,7 +55,7 @@ /* * Print appropriate message(s) if mail has arrived. If the argument is - * nozero, then the value of MAIL has changed, so we just update the + * non-zero, then the value of MAIL has changed, so we just update the * values. */ diff --git a/bin/sh/memalloc.c b/bin/sh/memalloc.c --- a/bin/sh/memalloc.c +++ b/bin/sh/memalloc.c @@ -283,7 +283,7 @@ /* - * The following routines are somewhat easier to use that the above. + * The following routines are somewhat easier to use than the above. * The user declares a variable of type STACKSTR, which may be declared * to be a register. The macro STARTSTACKSTR initializes things. Then * the user uses the macro STPUTC to add characters to the string. In diff --git a/contrib/llvm-project/libcxx/include/__system_error/errc.h b/contrib/llvm-project/libcxx/include/__system_error/errc.h --- a/contrib/llvm-project/libcxx/include/__system_error/errc.h +++ b/contrib/llvm-project/libcxx/include/__system_error/errc.h @@ -143,7 +143,9 @@ identifier_removed = EIDRM, illegal_byte_sequence = EILSEQ, inappropriate_io_control_operation = ENOTTY, +#ifdef EINTEGRITY integrity_check_failed = EINTEGRITY, +#endif interrupted = EINTR, invalid_argument = EINVAL, invalid_seek = ESPIPE, diff --git a/contrib/llvm-project/libcxx/include/errno.h b/contrib/llvm-project/libcxx/include/errno.h --- a/contrib/llvm-project/libcxx/include/errno.h +++ b/contrib/llvm-project/libcxx/include/errno.h @@ -34,79 +34,49 @@ #ifdef __cplusplus -#if !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) || !defined(EINTEGRITY) +#if !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) -#if defined(ELAST) +#ifdef ELAST static const int __elast1 = ELAST+1; static const int __elast2 = ELAST+2; -static const int __elast3 = ELAST+3; #else static const int __elast1 = 104; static const int __elast2 = 105; -static const int __elast3 = 106; #endif -#if !defined(EOWNERDEAD) && !defined(ENOTRECOVERABLE) && !defined(EINTEGRITY) -#define ENOTRECOVERABLE __elast1 -#define EOWNERDEAD __elast2 -#define EINTEGRITY __elast3 -#if defined(ELAST) -#undef ELAST -#define ELAST EINTEGRITY -#endif - -#elif !defined(EOWNERDEAD) && !defined(ENOTRECOVERABLE) && defined(EINTEGRITY) -#define ENOTRECOVERABLE __elast1 -#define EOWNERDEAD __elast2 -#if defined(ELAST) -#undef ELAST -#define ELAST EOWNERDEAD -#endif +#ifdef ENOTRECOVERABLE -#elif !defined(EOWNERDEAD) && defined(ENOTRECOVERABLE) && !defined(EINTEGRITY) #define EOWNERDEAD __elast1 -#define EINTEGRITY __elast2 -#if defined(ELAST) -#undef ELAST -#define ELAST EINTEGRITY -#endif -#elif !defined(EOWNERDEAD) && defined(ENOTRECOVERABLE) && defined(EINTEGRITY) -#define EOWNERDEAD __elast1 -#if defined(ELAST) +#ifdef ELAST #undef ELAST #define ELAST EOWNERDEAD #endif -#elif defined(EOWNERDEAD) && !defined(ENOTRECOVERABLE) && !defined(EINTEGRITY) -#define ENOTRECOVERABLE __elast1 -#define EINTEGRITY __elast2 -#if defined(ELAST) -#undef ELAST -#define ELAST EINTEGRITY -#endif +#elif defined(EOWNERDEAD) -#elif defined(EOWNERDEAD) && !defined(ENOTRECOVERABLE) && defined(EINTEGRITY) #define ENOTRECOVERABLE __elast1 -#if defined(ELAST) +#ifdef ELAST #undef ELAST #define ELAST ENOTRECOVERABLE #endif -#elif defined(EOWNERDEAD) && defined(ENOTRECOVERABLE) && !defined(EINTEGRITY) -#define EINTEGRITY __elast1 -#if defined(ELAST) +#else // defined(EOWNERDEAD) + +#define EOWNERDEAD __elast1 +#define ENOTRECOVERABLE __elast2 +#ifdef ELAST #undef ELAST -#define ELAST EINTEGRITY +#define ELAST ENOTRECOVERABLE #endif -#endif // !defined(OWNERDEAD) && !defined(NOTRECOVERABLE) && !defined(INTEGRITY) +#endif // defined(EOWNERDEAD) -#endif // !defined(OWNERDEAD) || !defined(NOTRECOVERABLE) || !defined(INTEGRITY) +#endif // !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) // supply errno values likely to be missing, particularly on Windows @@ -424,10 +394,6 @@ #define EMLINK 9979 #endif -#ifndef EINTEGRITY -#define EINTEGRITY 9980 -#endif - #endif // __cplusplus #endif // _LIBCPP_ERRNO_H diff --git a/contrib/telnet/telnet/telnet.c b/contrib/telnet/telnet/telnet.c --- a/contrib/telnet/telnet/telnet.c +++ b/contrib/telnet/telnet/telnet.c @@ -206,7 +206,7 @@ void DoBaudRate(char *arg) { - char *temp, temp2[10]; + char *temp, temp2[11]; int i; uint32_t baudrate; diff --git a/contrib/tzdata/Makefile b/contrib/tzdata/Makefile --- a/contrib/tzdata/Makefile +++ b/contrib/tzdata/Makefile @@ -1,7 +1,25 @@ # Make and install tzdb code and data. - # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. +# Request POSIX conformance; this must be the first non-comment line. +.POSIX: +# On older platforms you may need to scrounge for a POSIX-conforming 'make'. +# For example, on Solaris 10 (2005), use /usr/sfw/bin/gmake or +# /usr/xpg4/bin/make, not /usr/ccs/bin/make. + +# To affect how this Makefile works, you can run a shell script like this: +# +# #!/bin/sh +# make CC='gcc -std=gnu11' "$@" +# +# This example script is appropriate for a pre-2017 GNU/Linux system +# where a non-default setting is needed to support this package's use of C99. +# +# Alternatively, you can simply edit this Makefile to tailor the following +# macro definitions. + +############################################################################### +# Start of macros that one plausibly might want to tailor. # Package name for the code distribution. PACKAGE= tzcode @@ -191,8 +209,9 @@ # On some hosts, this should have -lintl unless CFLAGS has -DHAVE_GETTEXT=0. LDLIBS= -# Add the following to the end of the "CFLAGS=" line as needed to override -# defaults specified in the source code. "-DFOO" is equivalent to "-DFOO=1". +# Add the following to an uncommented "CFLAGS=" line as needed +# to override defaults specified in the source code or by the system. +# "-DFOO" is equivalent to "-DFOO=1". # -DDEPRECATE_TWO_DIGIT_YEARS for optional runtime warnings about strftime # formats that generate only the last two digits of year numbers # -DEPOCH_LOCAL if the 'time' function returns local time not UT @@ -234,11 +253,16 @@ # -DHAVE_UNISTD_H=0 if does not work* # -DHAVE_UTMPX_H=0 if does not work* # -Dlocale_t=XXX if your system uses XXX instead of locale_t -# -DPORT_TO_C89 if tzcode should also run on C89 platforms+ +# -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+ +# Typically it is better to use a later standard. For example, +# with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'. +# Even with -DPORT_TO_C89, the code needs at least one C99 +# feature (integers at least 64 bits wide) and maybe more. # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. # -Dssize_t=long on hosts like MS-Windows that lack ssize_t # -DSUPPORT_C89 if the tzcode library should support C89 callers+ +# However, this might trigger latent bugs in C99-or-later callers. # -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has # security implications and is not recommended for general use # -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires; @@ -270,11 +294,15 @@ # -DZIC_MAX_ABBR_LEN_WO_WARN=3 # (or some other number) to set the maximum time zone abbreviation length # that zic will accept without a warning (the default is 6) +# -g to generate symbolic debugging info +# -Idir to include from directory 'dir' +# -O0 to disable optimization; other -O options to enable more optimization +# -Uname to remove any definition of the macro 'name' # $(GCC_DEBUG_FLAGS) if you are using recent GCC and want lots of checking # # * Options marked "*" can be omitted if your compiler is C23 compatible. # * Options marked "+" are obsolescent and are planned to be removed -# once the code assumes C99 or later. +# once the code assumes C99 or later, say in the year 2029. # # Select instrumentation via "make GCC_INSTRUMENT='whatever'". GCC_INSTRUMENT = \ @@ -353,9 +381,11 @@ # functions to be added to the time conversion library. # "offtime" is like "gmtime" except that it accepts a second (long) argument # that gives an offset to add to the time_t when converting it. -# "timelocal" is equivalent to "mktime". +# I.e., "offtime" is like calling "localtime_rz" with a fixed-offset zone. +# "timelocal" is nearly equivalent to "mktime". # "timeoff" is like "timegm" except that it accepts a second (long) argument # that gives an offset to use when converting to a time_t. +# I.e., "timeoff" is like calling "mktime_z" with a fixed-offset zone. # "posix2time" and "time2posix" are described in an included manual page. # X3J11's work does not describe any of these functions. # These functions may well disappear in future releases of the time @@ -378,7 +408,7 @@ # # NIST-PCTS:151-2, Version 1.4, (1993-12-03) is a test suite put # out by the National Institute of Standards and Technology -# which claims to test C and Posix conformance. If you want to pass PCTS, add +# which claims to test C and POSIX conformance. If you want to pass PCTS, add # -DPCTS # to the end of the "CFLAGS=" line. # @@ -388,13 +418,21 @@ # 53 as a week number (rather than 52 or 53) for January days before # January's first Monday when a "%V" format is used and January 1 # falls on a Friday, Saturday, or Sunday. +# +# POSIX says CFLAGS defaults to "-O 1". +# Uncomment the following line and edit its contents as needed. -CFLAGS= +#CFLAGS= -O 1 -# Linker flags. Default to $(LFLAGS) for backwards compatibility -# to release 2012h and earlier. -LDFLAGS= $(LFLAGS) +# The name of a POSIX-like library archiver, its flags, C compiler, +# linker flags, and 'make' utility. Ordinarily the defaults suffice. +# The commented-out values are the defaults specified by POSIX 202x/D3. +#AR = ar +#ARFLAGS = -rv +#CC = c17 +#LDFLAGS = +#MAKE = make # For leap seconds, this Makefile uses LEAPSECONDS='-L leapseconds' in # submake command lines. The default is no leap seconds. @@ -418,18 +456,18 @@ ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' $(LEAPSECONDS) -# The name of a Posix-compliant 'awk' on your system. +# The name of a POSIX-compliant 'awk' on your system. # mawk 1.3.3 and Solaris 10 /usr/bin/awk do not work. # Also, it is better (though not essential) if 'awk' supports UTF-8, # and unfortunately mawk and busybox awk do not support UTF-8. # Try AWK=gawk or AWK=nawk if your awk has the abovementioned problems. AWK= awk -# The full path name of a Posix-compliant shell, preferably one that supports +# The full path name of a POSIX-compliant shell, preferably one that supports # the Korn shell's 'select' statement as an extension. # These days, Bash is the most popular. # It should be OK to set this to /bin/sh, on platforms where /bin/sh -# lacks 'select' or doesn't completely conform to Posix, but /bin/bash +# lacks 'select' or doesn't completely conform to POSIX, but /bin/bash # is typically nicer if it works. KSHELL= /bin/bash @@ -503,17 +541,16 @@ DIFF_TZS= diff -u$$(! diff -u -F'^TZ=' - - <>/dev/null >&0 2>&1 \ || echo ' -F^TZ=') -############################################################################### - -#MAKE= make +# ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib. +RANLIB= : -cc= cc -CC= $(cc) -DTZDIR='"$(TZDIR)"' +# POSIX prohibits defining or using SHELL. However, csh users on systems +# that use the user shell for Makefile commands may need to define SHELL. +#SHELL= /bin/sh -AR= ar +# End of macros that one plausibly might want to tailor. +############################################################################### -# ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib. -RANLIB= : TZCOBJS= zic.o TZDOBJS= zdump.o localtime.o asctime.o strftime.o @@ -543,7 +580,7 @@ NDATA= factory TDATA_TO_CHECK= $(YDATA) $(NDATA) backward TDATA= $(YDATA) $(NDATA) $(BACKWARD) -ZONETABLES= zone1970.tab zone.tab +ZONETABLES= zone.tab zone1970.tab zonenow.tab TABDATA= iso3166.tab $(TZDATA_TEXT) $(ZONETABLES) LEAP_DEPS= leapseconds.awk leap-seconds.list TZDATA_ZI_DEPS= ziguard.awk zishrink.awk version $(TDATA) \ @@ -551,7 +588,7 @@ DSTDATA_ZI_DEPS= ziguard.awk $(TDATA) $(PACKRATDATA) $(PACKRATLIST) DATA= $(TDATA_TO_CHECK) backzone iso3166.tab leap-seconds.list \ leapseconds $(ZONETABLES) -AWK_SCRIPTS= checklinks.awk checktab.awk leapseconds.awk \ +AWK_SCRIPTS= checklinks.awk checknow.awk checktab.awk leapseconds.awk \ ziguard.awk zishrink.awk MISC= $(AWK_SCRIPTS) TZS_YEAR= 2050 @@ -572,7 +609,7 @@ calendars CONTRIBUTING LICENSE Makefile NEWS README SECURITY \ africa antarctica asctime.c asia australasia \ backward backzone \ - checklinks.awk checktab.awk \ + checklinks.awk checknow.awk checktab.awk \ date.1 date.c difftime.c \ etcetera europe factory iso3166.tab \ leap-seconds.list leapseconds.awk localtime.c \ @@ -582,12 +619,7 @@ tzfile.5 tzfile.h tzselect.8 tzselect.ksh \ workman.sh zdump.8 zdump.c zic.8 zic.c \ ziguard.awk zishrink.awk \ - zone.tab zone1970.tab - -# And for the benefit of csh users on systems that assume the user -# shell should be used to handle commands in Makefiles. . . - -SHELL= /bin/sh + zone.tab zone1970.tab zonenow.tab all: tzselect zic zdump libtz.a $(TABDATA) \ vanguard.zi main.zi rearguard.zi @@ -657,6 +689,16 @@ $(DATAFORM).zi >$@.out mv $@.out $@ +tzdir.h: + printf '%s\n' >$@.out \ + '#ifndef TZDEFAULT' \ + '# define TZDEFAULT "$(TZDEFAULT)" /* default zone */' \ + '#endif' \ + '#ifndef TZDIR' \ + '# define TZDIR "$(TZDIR)" /* TZif directory */' \ + '#endif' + mv $@.out $@ + version.h: version VERSION=`cat version` && printf '%s\n' \ 'static char const PKGVERSION[]="($(PACKAGE)) ";' \ @@ -763,7 +805,7 @@ libtz.a: $(LIBOBJS) rm -f $@ - $(AR) -rc $@ $(LIBOBJS) + $(AR) $(ARFLAGS) $@ $(LIBOBJS) $(RANLIB) $@ date: $(DATEOBJS) @@ -771,26 +813,32 @@ tzselect: tzselect.ksh version VERSION=`cat version` && sed \ - -e 's|#!/bin/bash|#!$(KSHELL)|g' \ - -e 's|AWK=[^}]*|AWK='\''$(AWK)'\''|g' \ - -e 's|\(PKGVERSION\)=.*|\1='\''($(PACKAGE)) '\''|' \ - -e 's|\(REPORT_BUGS_TO\)=.*|\1=$(BUGEMAIL)|' \ - -e 's|TZDIR=[^}]*|TZDIR=$(TZDIR)|' \ - -e 's|\(TZVERSION\)=.*|\1='"$$VERSION"'|' \ - <$@.ksh >$@.out + -e "s'#!/bin/bash'#!"'$(KSHELL)'\' \ + -e s\''\(AWK\)=[^}]*'\''\1=\'\''$(AWK)\'\'\' \ + -e s\''\(PKGVERSION\)=.*'\''\1=\'\''($(PACKAGE)) \'\'\' \ + -e s\''\(REPORT_BUGS_TO\)=.*'\''\1=\'\''$(BUGEMAIL)\'\'\' \ + -e s\''\(TZDIR\)=[^}]*'\''\1=\'\''$(TZDIR)\'\'\' \ + -e s\''\(TZVERSION\)=.*'\''\1=\'"'$$VERSION\\''" \ + <$@.ksh >$@.out chmod +x $@.out mv $@.out $@ check: check_back check_mild check_mild: check_character_set check_white_space check_links \ - check_name_lengths check_slashed_abbrs check_sorted \ + check_name_lengths check_now \ + check_slashed_abbrs check_sorted \ check_tables check_web check_ziguard check_zishrink check_tzs +# True if UTF8_LOCALE does not work; +# otherwise, false but with LC_ALL set to $(UTF8_LOCALE). +UTF8_LOCALE_MISSING = \ + { test ! '$(UTF8_LOCALE)' \ + || ! printf 'A\304\200B\n' \ + | LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 \ + || { LC_ALL='$(UTF8_LOCALE)'; export LC_ALL; false; }; } + check_character_set: $(ENCHILADA) - test ! '$(UTF8_LOCALE)' || \ - ! printf 'A\304\200B\n' | \ - LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 || { \ - LC_ALL='$(UTF8_LOCALE)' && export LC_ALL && \ + $(UTF8_LOCALE_MISSING) || { \ sharp='#' && \ ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \ $(MISC) $(SOURCES) $(WEB_PAGES) \ @@ -805,12 +853,12 @@ touch $@ check_white_space: $(ENCHILADA) + $(UTF8_LOCALE_MISSING) || { \ patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \ - ! grep -En "$$pat" \ - $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list) - ! grep -n '[$s]$$' \ - $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list) - touch $@ + ! grep -En "$$pat|[$s]\$$" \ + $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list); \ + } + touch $@ PRECEDES_FILE_NAME = ^(Zone|Link[$s]+[^$s]+)[$s]+ FILE_NAME_COMPONENT_TOO_LONG = $(PRECEDES_FILE_NAME)[^$s]*[^/$s]{15} @@ -851,7 +899,29 @@ -f checklinks.awk tzdata.zi touch $@ -check_tables: checktab.awk $(YDATA) backward $(ZONETABLES) +# Check timestamps from now through 28 years from now, to make sure +# that zonenow.tab contains all sequences of planned timestamps, +# without any duplicate sequences. In theory this might require +# 2800 years but that would take a long time to check. +CHECK_NOW_TIMESTAMP = `./date +%s` +CHECK_NOW_FUTURE_YEARS = 28 +CHECK_NOW_FUTURE_SECS = $(CHECK_NOW_FUTURE_YEARS) '*' 366 '*' 24 '*' 60 '*' 60 +check_now: checknow.awk date tzdata.zi zdump zic zone1970.tab zonenow.tab + rm -fr $@.dir + mkdir $@.dir + ./zic -d $@.dir tzdata.zi + now=$(CHECK_NOW_TIMESTAMP) && \ + future=`expr $(CHECK_NOW_FUTURE_SECS) + $$now` && \ + ./zdump -i -t $$now,$$future \ + $$(find $$PWD/$@.dir/????*/ -type f) \ + >$@.dir/zdump.tab + $(AWK) \ + -v zdump_table=$@.dir/zdump.tab \ + -f checknow.awk zonenow.tab + rm -fr $@.dir + touch $@ + +check_tables: checktab.awk $(YDATA) backward zone.tab zone1970.tab for tab in $(ZONETABLES); do \ test "$$tab" = zone.tab && links='$(BACKWARD)' || links=''; \ $(AWK) -f checktab.awk -v zone_table=$$tab $(YDATA) $$links \ @@ -911,10 +981,10 @@ touch $@ clean_misc: - rm -fr check_*.dir + rm -fr check_*.dir typecheck_*.dir rm -f *.o *.out $(TIME_T_ALTERNATIVES) \ check_* core typecheck_* \ - date tzselect version.h zdump zic libtz.a + date tzdir.h tzselect version.h zdump zic libtz.a clean: clean_misc rm -fr *.dir tzdb-*/ rm -f *.zi $(TZS_NEW) @@ -952,12 +1022,18 @@ # plus N if GNU ls and touch are available. SET_TIMESTAMP_N = sh -c '\ n=$$0 dest=$$1; shift; \ - touch -cmr `ls -t "$$@" | sed 1q` "$$dest" && \ + <"$$dest" && \ if test $$n != 0 && \ - lsout=`ls -n --time-style="+%s" "$$dest" 2>/dev/null`; then \ + lsout=`ls -nt --time-style="+%s" "$$@" 2>/dev/null`; then \ set x $$lsout && \ - touch -cmd @`expr $$7 + $$n` "$$dest"; \ - else :; fi' + timestamp=`expr $$7 + $$n` && \ + echo "+ touch -md @$$timestamp $$dest" && \ + touch -md @$$timestamp "$$dest"; \ + else \ + newest=`ls -t "$$@" | sed 1q` && \ + echo "+ touch -mr $$newest $$dest" && \ + touch -mr "$$newest" "$$dest"; \ + fi' # If DEST depends on A B C ... in this Makefile, callers should use # $(SET_TIMESTAMP_DEP) DEST A B C ..., for the benefit of any # downstream 'make' that considers equal timestamps to be out of date. @@ -982,8 +1058,12 @@ rm -f test.out && \ for file in $$files; do \ if git diff --quiet $$file; then \ - time=`git log -1 --format='tformat:%ct' $$file` && \ - touch -cmd @$$time $$file; \ + time=`TZ=UTC0 git log -1 \ + --format='tformat:%cd' \ + --date='format:%Y-%m-%dT%H:%M:%SZ' \ + $$file` && \ + echo "+ touch -md $$time $$file" && \ + touch -md $$time $$file; \ else \ echo >&2 "$$file: warning: does not match repository"; \ fi || exit; \ @@ -1008,7 +1088,8 @@ rm -fr public.dir mkdir public.dir ln $(VERSION_DEPS) public.dir - cd public.dir && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' ALL + cd public.dir \ + && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' TZDIR='$(TZDIR)' ALL for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi \ public.dir/vanguard.zi public.dir/main.zi \ public.dir/rearguard.zi; \ @@ -1139,7 +1220,7 @@ sed '1s/$$/-rearguard/' $@.dir/version : The dummy pacificnew pacifies TZUpdater 2.3.1 and earlier. $(CREATE_EMPTY) $@.dir/pacificnew - touch -cmr version $@.dir/version + touch -mr version $@.dir/version LC_ALL=C && export LC_ALL && \ (cd $@.dir && \ tar $(TARFLAGS) -cf - \ @@ -1163,7 +1244,7 @@ `test $(DATAFORM) = vanguard || echo pacificnew` (grep '^#' tzdata.zi && echo && cat $(DATAFORM).zi) \ >$@.dir/etcetera - touch -cmr tzdata.zi $@.dir/etcetera + touch -mr tzdata.zi $@.dir/etcetera sed -n \ -e '/^# *version *\(.*\)/h' \ -e '/^# *ddeps */H' \ @@ -1174,7 +1255,7 @@ -e 's/ /-/g' \ -e 'p' \ $@.dir/version - touch -cmr version $@.dir/version + touch -mr version $@.dir/version links= && \ for file in $(TZDATA_DIST); do \ test -f $@.dir/$$file || links="$$links $$file"; \ @@ -1226,10 +1307,10 @@ asctime.o: private.h tzfile.h date.o: private.h difftime.o: private.h -localtime.o: private.h tzfile.h +localtime.o: private.h tzfile.h tzdir.h strftime.o: private.h tzfile.h zdump.o: version.h -zic.o: private.h tzfile.h version.h +zic.o: private.h tzfile.h tzdir.h version.h .PHONY: ALL INSTALL all .PHONY: check check_mild check_time_t_alternatives diff --git a/contrib/tzdata/NEWS b/contrib/tzdata/NEWS --- a/contrib/tzdata/NEWS +++ b/contrib/tzdata/NEWS @@ -1,5 +1,109 @@ News for the tz database +Release 2023d - 2023-12-21 20:02:24 -0800 + + Briefly: + Ittoqqortoormiit, Greenland changes time zones on 2024-03-31. + Vostok, Antarctica changed time zones on 2023-12-18. + Casey, Antarctica changed time zones five times since 2020. + Code and data fixes for Palestine timestamps starting in 2072. + A new data file zonenow.tab for timestamps starting now. + + Changes to future timestamps + + Ittoqqortoormiit, Greenland (America/Scoresbysund) joins most of + the rest of Greenland's timekeeping practice on 2024-03-31, by + changing its time zone from -01/+00 to -02/-01 at the same moment + as the spring-forward transition. Its clocks will therefore not + spring forward as previously scheduled. The time zone change + reverts to its common practice before 1981. + + Fix predictions for DST transitions in Palestine in 2072-2075, + correcting a typo introduced in 2023a. + + Changes to past and future timestamps + + Vostok, Antarctica changed to +05 on 2023-12-18. It had been at + +07 (not +06) for years. (Thanks to Zakhary V. Akulov.) + + Change data for Casey, Antarctica to agree with timeanddate.com, + by adding five time zone changes since 2020. Casey is now at +08 + instead of +11. + + Changes to past tm_isdst flags + + Much of Greenland, represented by America/Nuuk, changed its + standard time from -03 to -02 on 2023-03-25, not on 2023-10-28. + This does not affect UTC offsets, only the tm_isdst flag. + (Thanks to Thomas M. Steenholdt.) + + New data file + + A new data file zonenow.tab helps configure applications that use + timestamps dated from now on. This simplifies configuration, + since users choose from a smaller Zone set. The file's format is + experimental and subject to change. + + Changes to code + + localtime.c no longer mishandles TZif files that contain a single + transition into a DST regime. Previously, it incorrectly assumed + DST was in effect before the transition too. (Thanks to Alois + Treindl for debugging help.) + + localtime.c's timeoff no longer collides with OpenBSD 7.4. + + The C code now uses _Generic only if __STDC_VERSION__ says the + compiler is C11 or later. + + tzselect now optionally reads zonenow.tab, to simplify when + configuring only for timestamps dated from now on. + + tzselect no longer creates temporary files. + + tzselect no longer mishandles the following: + + Spaces and most other special characters in BUGEMAIL, PACKAGE, + TZDIR, and VERSION. + + TZ strings when using mawk 1.4.3, which mishandles regular + expressions of the form /X{2,}/. + + ISO 6709 coordinates when using an awk that lacks the GNU + extension of newlines in -v option-arguments. + + Non UTF-8 locales when using an iconv command that lacks the GNU + //TRANSLIT extension. + + zic no longer mishandles data for Palestine after the year 2075. + Previously, it incorrectly omitted post-2075 transitions that are + predicted for just before and just after Ramadan. (Thanks to Ken + Murchison for debugging help.) + + zic now works again on Linux 2.6.16 and 2.6.17 (2006). + (Problem reported by Rune Torgersen.) + + Changes to build procedure + + The Makefile is now more compatible with POSIX: + * It no longer defines AR, CC, CFLAGS, LDFLAGS, and SHELL. + * It no longer uses its own 'cc' in place of CC. + * It now uses ARFLAGS, with default specified by POSIX. + * It does not use LFLAGS incompatibly with POSIX. + * It uses the special .POSIX target. + * It quotes special characters more carefully. + * It no longer mishandles builds in an ISO 8859 locale. + Due to the CC changes, TZDIR is now #defined in a file tzfile.h + built by 'make', not in a $(CC) -D option. Also, TZDEFAULT is + now treated like TZDIR as they have similar roles. + + Changes to commentary + + Limitations and hazards of the optional support for obsolescent + C89 platforms are documented better, along with a tentative + schedule for removing this support. + + Release 2023c - 2023-03-28 12:42:14 -0700 Changes to past and future timestamps @@ -76,11 +180,14 @@ platform dependent and abbreviations were silently truncated to 16 bytes even when the limit was greater than 16. - The code by default is now designed for C99 or later. To build in - a C89 environment, compile with -DPORT_TO_C89. To support C89 - callers of the tzcode library, compile with -DSUPPORT_C89. The - two new macros are transitional aids planned to be removed in a - future version, when C99 or later will be required. + The code by default is now designed for C99 or later. To build on + a mostly-C89 platform, compile with -DPORT_TO_C89; this should + work on C89 platforms that also support C99 'long long' and + perhaps a few other extensions to C89. To support C89 callers of + tzcode's library, compile with -DSUPPORT_C89; however, this could + trigger latent bugs in C99-or-later callers. The two new macros + are transitional aids planned to be removed in a future version + (say, in 2029), when C99 or later will be required. The code now builds again on pre-C99 platforms, if you compile with -DPORT_TO_C89. This fixes a bug introduced in 2022f. @@ -723,6 +830,8 @@ them, set the EXPIRES_LINE Makefile variable. If a TZif file uses this new feature it is marked with a new TZif version number 4, a format intended to be documented in a successor to RFC 8536. + The old-format "#expires" comments are now treated solely as + comments and have no effect on the TZif files. zic -L LEAPFILE -r @LO no longer generates an invalid TZif file that omits leap second information for the range LO..B when LO @@ -4302,7 +4411,7 @@ now uses tz@iana.org rather than the old elsie address. zic -v now complains about abbreviations that are less than 3 - or more than 6 characters, as per Posix. Formerly, it checked + or more than 6 characters, as per POSIX. Formerly, it checked for abbreviations that were more than 3. 'make public' no longer puts its temporary directory under /tmp, @@ -4467,8 +4576,8 @@ In particular, the typos in comments in the data (2011-11-17 should have been 2011-10-17 as Alan Barrett noted, and spelling of Tiraspol that Tim Parenti noted) have been fixed, and the change for Ukraine has been - made in all 4 Ukrainian zones, rather than just Kiev (again, thanks to - Tim Parenti, and also Denys Gavrysh) + made in all 4 Ukrainian zones, rather than just Europe/Kiev + (again, thanks to Tim Parenti, and also Denys Gavrysh). In addition, I added Europe/Tiraspol to zone.tab. diff --git a/contrib/tzdata/README b/contrib/tzdata/README --- a/contrib/tzdata/README +++ b/contrib/tzdata/README @@ -11,14 +11,17 @@ and daylight-saving rules. See or the -file tz-link.html for how to acquire the code and data. Once acquired, -read the comments in the file 'Makefile' and make any changes needed -to make things right for your system, especially if you are using some -platform other than GNU/Linux. Then run the following commands, -substituting your desired installation directory for "$HOME/tzdir": - - make TOPDIR=$HOME/tzdir install - $HOME/tzdir/usr/bin/zdump -v America/Los_Angeles +file tz-link.html for how to acquire the code and data. + +Once acquired, read the leading comments in the file "Makefile" +and make any changes needed to make things right for your system, +especially when using a platform other than current GNU/Linux. + +Then run the following commands, substituting your desired +installation directory for "$HOME/tzdir": + + make TOPDIR="$HOME/tzdir" install + "$HOME/tzdir/usr/bin/zdump" -v America/Los_Angeles See the file tz-how-to.html for examples of how to read the data files. diff --git a/contrib/tzdata/africa b/contrib/tzdata/africa --- a/contrib/tzdata/africa +++ b/contrib/tzdata/africa @@ -285,13 +285,6 @@ # reproduced by other (more accessible) sites[, e.g.,]... # http://elgornal.net/news/news.aspx?id=4699258 -# From Paul Eggert (2014-06-04): -# Sarah El Deeb and Lee Keath of AP report that the Egyptian government says -# the change is because of blackouts in Cairo, even though Ahram Online (cited -# above) says DST had no affect on electricity consumption. There is -# no information about when DST will end this fall. See: -# http://abcnews.go.com/International/wireStory/el-sissi-pushes-egyptians-line-23614833 - # From Steffen Thorsen (2015-04-08): # Egypt will start DST on midnight after Thursday, April 30, 2015. # This is based on a law (no 35) from May 15, 2014 saying it starts the last diff --git a/contrib/tzdata/antarctica b/contrib/tzdata/antarctica --- a/contrib/tzdata/antarctica +++ b/contrib/tzdata/antarctica @@ -80,6 +80,11 @@ # - 2018 Oct 7 4:00 - 2019 Mar 17 3:00 - 2019 Oct 4 3:00 - 2020 Mar 8 3:00 # and now - 2020 Oct 4 0:01 +# From Paul Eggert (2023-12-20): +# Transitions from 2021 on are taken from: +# https://www.timeanddate.com/time/zone/antarctica/casey +# retrieved at various dates. + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2009 Oct 18 2:00 @@ -93,7 +98,12 @@ 8:00 - +08 2019 Oct 4 3:00 11:00 - +11 2020 Mar 8 3:00 8:00 - +08 2020 Oct 4 0:01 - 11:00 - +11 + 11:00 - +11 2021 Mar 14 0:00 + 8:00 - +08 2021 Oct 3 0:01 + 11:00 - +11 2022 Mar 13 0:00 + 8:00 - +08 2022 Oct 2 0:01 + 11:00 - +11 2023 Mar 9 3:00 + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 7:00 - +07 1964 Nov 0 - -00 1969 Feb @@ -240,7 +250,50 @@ # year-round from 1960/61 to 1992 # Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11 -# See Asia/Urumqi. +# From Craig Mundell (1994-12-15): +# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP +# Vostok, which is one of the Russian stations, is set on the same +# time as Moscow, Russia. +# +# From Lee Hotz (2001-03-08): +# I queried the folks at Columbia who spent the summer at Vostok and this is +# what they had to say about time there: +# "in the US Camp (East Camp) we have been on New Zealand (McMurdo) +# time, which is 12 hours ahead of GMT. The Russian Station Vostok was +# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead +# of GMT). This is a time zone I think two hours east of Moscow. The +# natural time zone is in between the two: 8 hours ahead of GMT." +# +# From Paul Eggert (2001-05-04): +# This seems to be hopelessly confusing, so I asked Lee Hotz about it +# in person. He said that some Antarctic locations set their local +# time so that noon is the warmest part of the day, and that this +# changes during the year and does not necessarily correspond to mean +# solar noon. So the Vostok time might have been whatever the clocks +# happened to be during their visit. So we still don't really know what time +# it is at Vostok. +# +# From Zakhary V. Akulov (2023-12-17 22:00:48 +0700): +# ... from December, 18, 2023 00:00 by my decision the local time of +# the Antarctic research base Vostok will correspond to UTC+5. +# (2023-12-19): We constantly interact with Progress base, with company who +# builds new wintering station, with sledge convoys, with aviation - they all +# use UTC+5. Besides, difference between Moscow time is just 2 hours now, not 4. +# (2023-12-19, in response to the question "Has local time at Vostok +# been UTC+6 ever since 1957, or has it changed before?"): No. At least +# since my antarctic career start, 10 years ago, Vostok base has UTC+7. +# (In response to a 2023-12-18 question "from 02:00 to 00:00 today"): This. +# +# From Paul Eggert (2023-12-18): +# For lack of better info, guess Vostok was at +07 from founding through today, +# except when closed. + +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone Antarctica/Vostok 0 - -00 1957 Dec 16 + 7:00 - +07 1994 Feb + 0 - -00 1994 Nov + 7:00 - +07 2023 Dec 18 2:00 + 5:00 - +05 # S Africa - year-round bases # Marion Island, -4653+03752 diff --git a/contrib/tzdata/asia b/contrib/tzdata/asia --- a/contrib/tzdata/asia +++ b/contrib/tzdata/asia @@ -655,7 +655,6 @@ 8:00 PRC C%sT # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) -# Vostok base in Antarctica matches this since 1970. Zone Asia/Urumqi 5:50:20 - LMT 1928 6:00 - +06 @@ -3427,6 +3426,9 @@ # From Heba Hamad (2023-03-22): # ... summer time will begin in Palestine from Saturday 04-29-2023, # 02:00 AM by 60 minutes forward. +# From Heba Hemad (2023-10-09): +# ... winter time will begin in Palestine from Saturday 10-28-2023, +# 02:00 AM by 60 minutes back. # # From Paul Eggert (2023-03-22): # For now, guess that spring and fall transitions will normally @@ -3548,13 +3550,13 @@ Rule Palestine 2071 only - Sep 19 2:00 0 - Rule Palestine 2072 only - Sep 10 2:00 0 - Rule Palestine 2072 only - Oct 15 2:00 1:00 S +Rule Palestine 2072 max - Oct Sat<=30 2:00 0 - Rule Palestine 2073 only - Sep 2 2:00 0 - Rule Palestine 2073 only - Oct 7 2:00 1:00 S Rule Palestine 2074 only - Aug 18 2:00 0 - Rule Palestine 2074 only - Sep 29 2:00 1:00 S Rule Palestine 2075 only - Aug 10 2:00 0 - Rule Palestine 2075 only - Sep 14 2:00 1:00 S -Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - Rule Palestine 2076 only - Jul 25 2:00 0 - Rule Palestine 2076 only - Sep 5 2:00 1:00 S Rule Palestine 2077 only - Jul 17 2:00 0 - diff --git a/contrib/tzdata/australasia b/contrib/tzdata/australasia --- a/contrib/tzdata/australasia +++ b/contrib/tzdata/australasia @@ -391,8 +391,14 @@ # Please note that there will not be any daylight savings time change # in Fiji for 2022-2023.... # https://www.facebook.com/FijianGovernment/posts/pfbid0mmWVTYmTibn66ybpFda75pDcf34SSpoSaskJW5gXwaKo5Sgc7273Q4fXWc6kQV6Hl + +# From Almaz Mingaleev (2023-10-06): +# Cabinet approved the suspension of Daylight Saving and appropriate +# legislative changes will be considered including the repeal of the +# Daylight Saving Act 1998 +# https://www.fiji.gov.fj/Media-Centre/Speeches/English/CABINET-DECISIONS-3-OCTOBER-2023 # -# From Paul Eggert (2022-10-27): +# From Paul Eggert (2023-10-06): # For now, assume DST is suspended indefinitely. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S diff --git a/contrib/tzdata/backward b/contrib/tzdata/backward --- a/contrib/tzdata/backward +++ b/contrib/tzdata/backward @@ -205,7 +205,6 @@ Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/contrib/tzdata/backzone b/contrib/tzdata/backzone --- a/contrib/tzdata/backzone +++ b/contrib/tzdata/backzone @@ -963,35 +963,6 @@ Zone Antarctica/Syowa 0 - -00 1957 Jan 29 3:00 - +03 -# Vostok, Antarctica -# -# Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11 -# From Craig Mundell (1994-12-15): -# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP -# Vostok, which is one of the Russian stations, is set on the same -# time as Moscow, Russia. -# -# From Lee Hotz (2001-03-08): -# I queried the folks at Columbia who spent the summer at Vostok and this is -# what they had to say about time there: -# "in the US Camp (East Camp) we have been on New Zealand (McMurdo) -# time, which is 12 hours ahead of GMT. The Russian Station Vostok was -# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead -# of GMT). This is a time zone I think two hours east of Moscow. The -# natural time zone is in between the two: 8 hours ahead of GMT." -# -# From Paul Eggert (2001-05-04): -# This seems to be hopelessly confusing, so I asked Lee Hotz about it -# in person. He said that some Antarctic locations set their local -# time so that noon is the warmest part of the day, and that this -# changes during the year and does not necessarily correspond to mean -# solar noon. So the Vostok time might have been whatever the clocks -# happened to be during their visit. So we still don't really know what time -# it is at Vostok. But we'll guess +06. -# -Zone Antarctica/Vostok 0 - -00 1957 Dec 16 - 6:00 - +06 - # Yemen # Milne says 2:59:54 was the meridian of the saluting battery at Aden, # and that Yemen was at 1:55:56, the meridian of the Hagia Sophia. diff --git a/contrib/tzdata/checknow.awk b/contrib/tzdata/checknow.awk new file mode 100644 --- /dev/null +++ b/contrib/tzdata/checknow.awk @@ -0,0 +1,54 @@ +# Check zonenow.tab for consistency with primary data. + +# Contributed by Paul Eggert. This file is in the public domain. + +function record_zone(zone, data) { + if (zone) { + zone_data[zone] = data + zones[data] = zones[data] " " zone + } +} + +BEGIN { + while (getline >"/dev/stderr" status = 1 @@ -110,7 +110,7 @@ used_max_cc = cc } } - if (used_max <= 1 && comments) { + if (used_max <= 1 && comments && zone_table != "zonenow.tab") { printf "%s:%d: unnecessary comment '%s'\n", \ zone_table, i, comments \ >>"/dev/stderr" @@ -149,7 +149,8 @@ if ($3 ~ /%/) rulePercentUsed[$2] = 1 } if (tz && tz ~ /\// && tz !~ /^Etc\//) { - if (!tztab[tz] && FILENAME != "backward") { + if (!tztab[tz] && FILENAME != "backward" \ + && zone_table != "zonenow.tab") { printf "%s: no data for '%s'\n", zone_table, tz \ >>"/dev/stderr" status = 1 diff --git a/contrib/tzdata/europe b/contrib/tzdata/europe --- a/contrib/tzdata/europe +++ b/contrib/tzdata/europe @@ -1123,6 +1123,23 @@ # 2. The shift *from* DST in 2023 happens as normal, but coincides with the # shift to UTC-02 normaltime (people will not change their clocks here). # 3. After this, DST is still observed, but as -02/-01 instead of -03/-02. +# +# From Múte Bourup Egede via Jógvan Svabo Samuelsen (2023-03-15): +# Greenland will not switch to Daylight Saving Time this year, 2023, +# because the standard time for Greenland will change from UTC -3 to UTC -2. +# However, Greenland will change to Daylight Saving Time again in 2024 +# and onwards. + +# From a contributor who wishes to remain anonymous for now (2023-10-29): +# https://www.dr.dk/nyheder/seneste/i-nat-skal-uret-stilles-en-time-tilbage-men-foerste-gang-sker-det-ikke-i-groenland +# with a link to that page: +# https://naalakkersuisut.gl/Nyheder/2023/10/2710_sommertid +# ... Ittoqqortoormiit joins the time of Nuuk at March 2024. +# What would mean that America/Scoresbysund would either be in -01 year round +# or in -02/-01 like America/Nuuk, but no longer in -01/+00. +# +# From Paul Eggert (2023-10-29): +# For now, assume it will be like America/Nuuk. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D @@ -1143,10 +1160,12 @@ Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -2:00 - -02 1980 Apr 6 2:00 -2:00 C-Eur -02/-01 1981 Mar 29 - -1:00 EU -01/+00 + -1:00 EU -01/+00 2024 Mar 31 + -2:00 EU -02/-01 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Oct 29 1:00u + -3:00 EU -03/-02 2023 Mar 26 1:00u + -2:00 - -02 2023 Oct 29 1:00u -2:00 EU -02/-01 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -3711,11 +3730,7 @@ # and not at 3:00 as would have been under EU rules. # This is why I have set the change to EU rules into May 1996, # so that the change in March is stil covered by the Ukraine rule. -# The next change in October 1996 happened under EU rules.... -# TZ database holds three other zones for Ukraine.... I have not yet -# worked out the consequences for these three zones, as we (me and my -# US colleague David Cochrane) are still trying to get more -# information upon these local deviations from Kiev rules. +# The next change in October 1996 happened under EU rules. # # From Paul Eggert (2022-08-27): # For now, assume that Ukraine's zones all followed the same rules, diff --git a/contrib/tzdata/leap-seconds.list b/contrib/tzdata/leap-seconds.list --- a/contrib/tzdata/leap-seconds.list +++ b/contrib/tzdata/leap-seconds.list @@ -204,10 +204,10 @@ # current -- the update time stamp, the data and the name of the file # will not change. # -# Updated through IERS Bulletin C65 -# File expires on: 28 December 2023 +# Updated through IERS Bulletin C66 +# File expires on: 28 June 2024 # -#@ 3912710400 +#@ 3928521600 # 2272060800 10 # 1 Jan 1972 2287785600 11 # 1 Jul 1972 @@ -252,4 +252,4 @@ # the hash line is also ignored in the # computation. # -#h e76a99dc 65f15cc7 e613e040 f5078b5e b23834fe +#h 16edd0f0 3666784f 37db6bdd e74ced87 59af48f1 diff --git a/contrib/tzdata/leapseconds b/contrib/tzdata/leapseconds --- a/contrib/tzdata/leapseconds +++ b/contrib/tzdata/leapseconds @@ -72,11 +72,11 @@ # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2023 Dec 28 00:00:00 +#Expires 2024 Jun 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1703721600 (2023-12-28 00:00:00 UTC) +#expires 1719532800 (2024-06-28 00:00:00 UTC) -# Updated through IERS Bulletin C65 -# File expires on: 28 December 2023 +# Updated through IERS Bulletin C66 +# File expires on: 28 June 2024 diff --git a/contrib/tzdata/northamerica b/contrib/tzdata/northamerica --- a/contrib/tzdata/northamerica +++ b/contrib/tzdata/northamerica @@ -1453,7 +1453,7 @@ Rule StJohns 2007 2011 - Mar Sun>=8 0:01 1:00 D Rule StJohns 2007 2010 - Nov Sun>=1 0:01 0 S # -# St John's has an apostrophe, but Posix file names can't have apostrophes. +# St John's has an apostrophe, but POSIX file names can't have apostrophes. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/St_Johns -3:30:52 - LMT 1884 -3:30:52 StJohns N%sT 1918 diff --git a/contrib/tzdata/southamerica b/contrib/tzdata/southamerica --- a/contrib/tzdata/southamerica +++ b/contrib/tzdata/southamerica @@ -1697,6 +1697,12 @@ # From Carlos Raúl Perasso (2014-02-28): # Decree 1264 can be found at: # http://www.presidencia.gov.py/archivos/documentos/DECRETO1264_ey9r8zai.pdf +# +# From Paul Eggert (2023-07-26): +# Transition dates are now set by Law No. 7115, not by presidential decree. +# https://www.abc.com.py/politica/2023/07/12/promulgacion-el-cambio-de-hora-sera-por-ley/ +# From Carlos Raúl Perasso (2023-07-27): +# http://silpy.congreso.gov.py/descarga/ley-144138 Rule Para 2013 max - Mar Sun>=22 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] diff --git a/contrib/tzdata/version b/contrib/tzdata/version --- a/contrib/tzdata/version +++ b/contrib/tzdata/version @@ -1 +1 @@ -2023c +2023d diff --git a/contrib/tzdata/zone.tab b/contrib/tzdata/zone.tab --- a/contrib/tzdata/zone.tab +++ b/contrib/tzdata/zone.tab @@ -48,7 +48,7 @@ AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -87,7 +87,7 @@ BO -1630-06809 America/La_Paz BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Para (east); Amapa +BR -0127-04829 America/Belem Para (east), Amapa BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -107,21 +107,21 @@ BW -2439+02555 Africa/Gaborone BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) -CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) @@ -207,8 +207,8 @@ HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man @@ -355,7 +355,7 @@ RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali @@ -418,7 +418,7 @@ US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US +332654-1120424 America/Phoenix MST - AZ (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/contrib/tzdata/zone1970.tab b/contrib/tzdata/zone1970.tab --- a/contrib/tzdata/zone1970.tab +++ b/contrib/tzdata/zone1970.tab @@ -38,7 +38,7 @@ #country- #codes coordinates TZ comments AD +4230+00131 Europe/Andorra -AE,OM,RE,SC,TF +2518+05518 Asia/Dubai Crozet, Scattered Is +AE,OM,RE,SC,TF +2518+05518 Asia/Dubai Crozet AF +3431+06912 Asia/Kabul AL +4120+01950 Europe/Tirane AM +4011+04430 Asia/Yerevan @@ -48,12 +48,13 @@ AQ -6448-06406 Antarctica/Palmer Palmer AQ -6734-06808 Antarctica/Rothera Rothera AQ -720041+0023206 Antarctica/Troll Troll +AQ -7824+10654 Antarctica/Vostok Vostok AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) AR -3124-06411 America/Argentina/Cordoba most areas: CB, CC, CN, ER, FM, MN, SE, SF AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucumán (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -82,7 +83,7 @@ BM +3217-06446 Atlantic/Bermuda BO -1630-06809 America/La_Paz BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Pará (east); Amapá +BR -0127-04829 America/Belem Pará (east), Amapá BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -100,19 +101,19 @@ BT +2728+08939 Asia/Thimphu BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) -CA,BS +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA,BS +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) @@ -127,7 +128,7 @@ CL -5309-07055 America/Punta_Arenas Region of Magallanes CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time -CN,AQ +4348+08735 Asia/Urumqi Xinjiang Time, Vostok +CN +4348+08735 Asia/Urumqi Xinjiang Time CO +0436-07405 America/Bogota CR +0956-08405 America/Costa_Rica CU +2308-08222 America/Havana @@ -172,8 +173,8 @@ HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IN +2232+08822 Asia/Kolkata @@ -252,7 +253,7 @@ PL +5215+02100 Europe/Warsaw PM +4703-05620 America/Miquelon PN -2504-13005 Pacific/Pitcairn -PR,AG,CA,AI,AW,BL,BQ,CW,DM,GD,GP,KN,LC,MF,MS,SX,TT,VC,VG,VI +182806-0660622 America/Puerto_Rico AST +PR,AG,CA,AI,AW,BL,BQ,CW,DM,GD,GP,KN,LC,MF,MS,SX,TT,VC,VG,VI +182806-0660622 America/Puerto_Rico AST - QC (Lower North Shore) PS +3130+03428 Asia/Gaza Gaza Strip PS +313200+0350542 Asia/Hebron West Bank PT +3843-00908 Europe/Lisbon Portugal (mainland) @@ -288,7 +289,7 @@ RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea SA,AQ,KW,YE +2438+04643 Asia/Riyadh Syowa @@ -330,7 +331,7 @@ US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US,CA +332654-1120424 America/Phoenix MST - AZ (most areas), Creston BC US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/contrib/tzdata/zonenow.tab b/contrib/tzdata/zonenow.tab new file mode 100644 --- /dev/null +++ b/contrib/tzdata/zonenow.tab @@ -0,0 +1,301 @@ +# tzdb timezone descriptions, for users who do not care about old timestamps +# +# This file is in the public domain. +# +# From Paul Eggert (2023-12-18): +# This file contains a table where each row stands for a timezone +# where civil timestamps are predicted to agree from now on. +# This file is like zone1970.tab (see zone1970.tab's coments), +# but with the following changes: +# +# 1. Each timezone corresponds to a set of clocks that are planned +# to agree from now on. This is a larger set of clocks than in +# zone1970.tab, where each timezone's clocks must agree from 1970 on. +# 2. The first column is irrelevant and ignored. +# 3. The table is sorted in a different way: +# first by standard time UTC offset; +# then, if DST is used, by daylight saving UTC offset; +# then by time zone abbreviation. +# 4. Every timezone has a nonempty comments column, with wording +# distinguishing the timezone only from other timezones with the +# same UTC offset at some point during the year. +# +# The format of this table is experimental, and may change in future versions. +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#XX coordinates TZ comments +# +# -11 - SST +XX -1416-17042 Pacific/Pago_Pago Midway; Samoa ("SST") +# +# -11 +XX -1901-16955 Pacific/Niue Niue +# +# -10 - HST +XX +211825-1575130 Pacific/Honolulu Hawaii ("HST") +# +# -10 +XX -1732-14934 Pacific/Tahiti Tahiti; Cook Islands +# +# -10/-09 - HST / HDT (North America DST) +XX +515248-1763929 America/Adak western Aleutians in Alaska ("HST/HDT") +# +# -09:30 +XX -0900-13930 Pacific/Marquesas Marquesas +# +# -09 +XX -2308-13457 Pacific/Gambier Gambier +# +# -09/-08 - AKST/AKDT (North America DST) +XX +611305-1495401 America/Anchorage most of Alaska ("AKST/AKDT") +# +# -08 +XX -2504-13005 Pacific/Pitcairn Pitcairn +# +# -08/-07 - PST/PDT (North America DST) +XX +340308-1181434 America/Los_Angeles Pacific ("PST/PDT") - US & Canada; Mexico near US border +# +# -07 - MST +XX +332654-1120424 America/Phoenix Mountain Standard ("MST") - Arizona; western Mexico; Yukon +# +# -07/-06 - MST/MDT (North America DST) +XX +394421-1045903 America/Denver Mountain ("MST/MDT") - US & Canada; Mexico near US border +# +# -06 +XX -0054-08936 Pacific/Galapagos Galápagos +# +# -06 - CST +XX +1924-09909 America/Mexico_City Central Standard ("CST") - Saskatchewan; central Mexico; Central America +# +# -06/-05 (Chile DST) +XX -2709-10926 Pacific/Easter Easter Island +# +# -06/-05 - CST/CDT (North America DST) +XX +415100-0873900 America/Chicago Central ("CST/CDT") - US & Canada; Mexico near US border +# +# -05 +XX -1203-07703 America/Lima eastern South America +# +# -05 - EST +XX +175805-0764736 America/Jamaica Eastern Standard ("EST") - Caymans; Jamaica; eastern Mexico; Panama +# +# -05/-04 - CST/CDT (Cuba DST) +XX +2308-08222 America/Havana Cuba +# +# -05/-04 - EST/EDT (North America DST) +XX +404251-0740023 America/New_York Eastern ("EST/EDT") - US & Canada +# +# -04 +XX +1030-06656 America/Caracas western South America +# +# -04 - AST +XX +1828-06954 America/Santo_Domingo Atlantic Standard ("AST") - eastern Caribbean +# +# -04/-03 (Chile DST) +XX -3327-07040 America/Santiago most of Chile +# +# -04/-03 (Paraguay DST) +XX -2516-05740 America/Asuncion Paraguay +# +# -04/-03 - AST/ADT (North America DST) +XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda +# +# -03:30/-02:30 - NST/NDT (North America DST) +XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") +# +# -03 +XX -2332-04637 America/Sao_Paulo eastern South America +# +# -03/-02 (North America DST) +XX +4703-05620 America/Miquelon St Pierre & Miquelon +# +# -02 +XX -0351-03225 America/Noronha Fernando de Noronha; South Georgia +# +# -02/-01 (EU DST) +XX +6411-05144 America/Nuuk most of Greenland +# +# -01 +XX +1455-02331 Atlantic/Cape_Verde Cape Verde +# +# -01/+00 (EU DST) +XX +3744-02540 Atlantic/Azores Azores +# -01/+00 (EU DST) until 2024-03-31; then -02/-01 (EU DST) +XX +7029-02158 America/Scoresbysund Ittoqqortoormiit +# +# +00 - GMT +XX +0519-00402 Africa/Abidjan far western Africa; Iceland ("GMT") +# +# +00/+01 - GMT/BST (EU DST) +XX +513030-0000731 Europe/London United Kingdom ("GMT/BST") +# +# +00/+01 - WET/WEST (EU DST) +XX +3843-00908 Europe/Lisbon western Europe ("WET/WEST") +# +# +00/+02 - Troll DST +XX -720041+0023206 Antarctica/Troll Troll Station in Antarctica +# +# +01 - CET +XX +3647+00303 Africa/Algiers Algeria, Tunisia ("CET") +# +# +01 - WAT +XX +0627+00324 Africa/Lagos western Africa ("WAT") +# +# +01/+00 - IST/GMT (EU DST in reverse) +XX +5320-00615 Europe/Dublin Ireland ("IST/GMT") +# +# +01/+00 - (Morocco DST) +XX +3339-00735 Africa/Casablanca Morocco +# +# +01/+02 - CET/CEST (EU DST) +XX +4852+00220 Europe/Paris central Europe ("CET/CEST") +# +# +02 - CAT +XX -2558+03235 Africa/Maputo central Africa ("CAT") +# +# +02 - EET +XX +3254+01311 Africa/Tripoli Libya; Kaliningrad ("EET") +# +# +02 - SAST +XX -2615+02800 Africa/Johannesburg southern Africa ("SAST") +# +# +02/+03 - EET/EEST (EU DST) +XX +3758+02343 Europe/Athens eastern Europe ("EET/EEST") +# +# +02/+03 - EET/EEST (Egypt DST) +XX +3003+03115 Africa/Cairo Egypt +# +# +02/+03 - EET/EEST (Lebanon DST) +XX +3353+03530 Asia/Beirut Lebanon +# +# +02/+03 - EET/EEST (Moldova DST) +XX +4700+02850 Europe/Chisinau Moldova +# +# +02/+03 - EET/EEST (Palestine DST) +XX +3130+03428 Asia/Gaza Palestine +# +# +02/+03 - IST/IDT (Israel DST) +XX +314650+0351326 Asia/Jerusalem Israel +# +# +03 +XX +4101+02858 Europe/Istanbul Near East; Belarus +# +# +03 - EAT +XX -0117+03649 Africa/Nairobi eastern Africa ("EAT") +# +# +03 - MSK +XX +554521+0373704 Europe/Moscow Moscow ("MSK") +# +# +03:30 +XX +3540+05126 Asia/Tehran Iran +# +# +04 +XX +2518+05518 Asia/Dubai Russia; Caucasus; Persian Gulf; Seychelles; Réunion +# +# +04:30 +XX +3431+06912 Asia/Kabul Afghanistan +# +# +05 +XX +4120+06918 Asia/Tashkent Russia; Tajikistan; Turkmenistan; Uzbekistan; Maldives +# +# +05 - PKT +XX +2452+06703 Asia/Karachi Pakistan ("PKT") +# +# +05:30 +XX +0656+07951 Asia/Colombo Sri Lanka +# +# +05:30 - IST +XX +2232+08822 Asia/Kolkata India ("IST") +# +# +05:45 +XX +2743+08519 Asia/Kathmandu Nepal +# +# +06 +XX +2343+09025 Asia/Dhaka Russia; Kyrgyzstan; Bhutan; Bangladesh; Chagos +# +# +06:30 +XX +1647+09610 Asia/Yangon Myanmar; Cocos +# +# +07 +XX +1345+10031 Asia/Bangkok Russia; Indochina; Christmas Island +# +# +07 - WIB +XX -0610+10648 Asia/Jakarta Indonesia ("WIB") +# +# +08 +XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore +# +# +08 - AWST +XX -3157+11551 Australia/Perth Western Australia ("AWST") +# +# +08 - CST +XX +3114+12128 Asia/Shanghai China ("CST") +# +# +08 - HKT +XX +2217+11409 Asia/Hong_Kong Hong Kong ("HKT") +# +# +08 - PHT +XX +1435+12100 Asia/Manila Philippines ("PHT") +# +# +08 - WITA +XX -0507+11924 Asia/Makassar Indonesia ("WITA") +# +# +08:45 +XX -3143+12852 Australia/Eucla Eucla +# +# +09 +XX +5203+11328 Asia/Chita Russia; Palau; East Timor +# +# +09 - JST +XX +353916+1394441 Asia/Tokyo Japan ("JST") +# +# +09 - KST +XX +3733+12658 Asia/Seoul Korea ("KST") +# +# +09 - WIT +XX -0232+14042 Asia/Jayapura Indonesia ("WIT") +# +# +09:30 - ACST +XX -1228+13050 Australia/Darwin Northern Territory ("ACST") +# +# +09:30/+10:30 - ACST/ACDT (Australia DST) +XX -3455+13835 Australia/Adelaide South Australia ("ACST/ACDT") +# +# +10 +XX +4310+13156 Asia/Vladivostok Russia; Yap; Chuuk; Papua New Guinea; Dumont d'Urville +# +# +10 - AEST +XX -2728+15302 Australia/Brisbane Queensland ("AEST") +# +# +10 - ChST +XX +1328+14445 Pacific/Guam Mariana Islands ("ChST") +# +# +10/+11 - AEST/AEDT (Australia DST) +XX -3352+15113 Australia/Sydney southeast Australia ("AEST/AEDT") +# +# +10:30/+11 +XX -3133+15905 Australia/Lord_Howe Lord Howe Island +# +# +11 +XX -0613+15534 Pacific/Bougainville Russia; Kosrae; Bougainville; Solomons +# +# +11/+12 (Australia DST) +XX -2903+16758 Pacific/Norfolk Norfolk Island +# +# +12 +XX +5301+15839 Asia/Kamchatka Russia; Tuvalu; Fiji; etc. +# +# +12/+13 (New Zealand DST) +XX -3652+17446 Pacific/Auckland New Zealand ("NZST/NZDT") +# +# +12:45/+13:45 (Chatham DST) +XX -4357-17633 Pacific/Chatham Chatham Islands +# +# +13 +XX -210800-1751200 Pacific/Tongatapu Kanton; Tokelau; Samoa (western); Tonga +# +# +14 +XX +0152-15720 Pacific/Kiritimati Kiritimati diff --git a/lib/libc++/Makefile b/lib/libc++/Makefile --- a/lib/libc++/Makefile +++ b/lib/libc++/Makefile @@ -867,6 +867,7 @@ MDS_HEADERS+= extents.h MDS_HEADERS+= layout_left.h MDS_HEADERS+= layout_right.h +MDS_HEADERS+= mdspan.h .for hdr in ${MDS_HEADERS} MDS+= ${HDRDIR}/__mdspan/${hdr} .endfor diff --git a/lib/libc/amd64/string/Makefile.inc b/lib/libc/amd64/string/Makefile.inc --- a/lib/libc/amd64/string/Makefile.inc +++ b/lib/libc/amd64/string/Makefile.inc @@ -3,17 +3,28 @@ bcmp.S \ memchr.S \ memcmp.S \ + memccpy.S \ memcpy.S \ memmove.S \ + memrchr.S \ memset.S \ stpcpy.S \ + stpncpy.S \ strcat.S \ strchrnul.S \ strcmp.S \ strcpy.c \ strcspn.S \ + strlcat.c \ + strlcpy.S \ strlen.S \ + strncat.c \ + strncmp.S \ + strncpy.c \ strnlen.c \ + strpbrk.c \ + strrchr.S \ + strsep.c \ strspn.S \ timingsafe_bcmp.S \ timingsafe_memcmp.S diff --git a/lib/libc/amd64/string/memccpy.S b/lib/libc/amd64/string/memccpy.S new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/memccpy.S @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 + +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4, 0x90 + + .weak memccpy + .set memccpy, __memccpy +ARCHFUNCS(__memccpy) + ARCHFUNC(__memccpy, scalar) + ARCHFUNC(__memccpy, baseline) +ENDARCHFUNCS(__memccpy) + +ARCHENTRY(__memccpy, scalar) + push %rbp # establish stack frame + mov %rsp, %rbp + push %rax # dummy push for alignment + push %rbx + push %rdi + push %rsi + + mov %rsi, %rdi + mov %edx, %esi + mov %rcx, %rdx + mov %rcx, %rbx + call CNAME(__memchr) # ptr = memchr(src, c, len) + + pop %rsi + pop %rdi + lea 1(%rax), %rdx + sub %rsi, %rdx # size = ptr - src + 1 + mov %rbx, %rcx + lea (%rdi, %rdx, 1), %rbx # res = dest + size + test %rax, %rax # if (ptr == NULL) + cmovz %rcx, %rdx # size = len + cmovz %rax, %rbx # res = NULL + call CNAME(memcpy) + + mov %rbx, %rax # return (res) + pop %rbx + leave + ret +ARCHEND(__memccpy, scalar) + +ARCHENTRY(__memccpy, baseline) + sub $1, %rcx # RCX refers to last character in buffer + jb .L0 # go to special code path if len was 0 + + movd %edx, %xmm4 + mov %rcx, %rdx + punpcklbw %xmm4, %xmm4 # c -> cc + mov %esi, %ecx + punpcklwd %xmm4, %xmm4 # cc -> cccc + mov %rsi, %r9 # stash a copy of the source pointer for later + pshufd $0, %xmm4, %xmm4 # cccc -> cccccccccccccccc + and $~0xf, %rsi + movdqa %xmm4, %xmm1 + pcmpeqb (%rsi), %xmm1 # NUL found in head? + mov $-1, %r8d + and $0xf, %ecx + shl %cl, %r8d # mask of bytes in the string + pmovmskb %xmm1, %eax + and %r8d, %eax + jnz .Lhead_nul + + movdqa 16(%rsi), %xmm3 # load second string chunk + movdqu (%r9), %xmm2 # load unaligned string head + mov $32, %r8d + sub %ecx, %r8d # head length + length of second chunk + movdqa %xmm4, %xmm1 + pcmpeqb %xmm3, %xmm1 # NUL found in second chunk? + + sub %r8, %rdx # enough space left for the second chunk? + jb .Lhead_buf_end + + /* process second chunk */ + pmovmskb %xmm1, %eax + test %eax, %eax + jnz .Lsecond_nul + + /* string didn't end in second chunk and neither did buffer -- not a runt! */ + movdqa 32(%rsi), %xmm0 # load next string chunk + movdqa %xmm4, %xmm1 + movdqu %xmm2, (%rdi) # deposit head into buffer + sub %rcx, %rdi # adjust RDI to correspond to RSI + movdqu %xmm3, 16(%rdi) # deposit second chunk + sub %rsi, %rdi # express RDI as distance from RSI + add $32, %rsi # advance RSI past first two chunks + sub $16, %rdx # enough left for another round? + jb 1f + + /* main loop unrolled twice */ + ALIGN_TEXT +0: pcmpeqb %xmm0, %xmm1 # NUL byte encountered? + pmovmskb %xmm1, %eax + test %eax, %eax + jnz 3f + + movdqu %xmm0, (%rsi, %rdi) + movdqa 16(%rsi), %xmm0 # load next string chunk + movdqa %xmm4, %xmm1 + cmp $16, %rdx # more than a full chunk left? + jb 2f + + add $32, %rsi # advance pointers to next chunk + pcmpeqb %xmm0, %xmm1 # NUL byte encountered? + pmovmskb %xmm1, %eax + test %eax, %eax + jnz 4f + + movdqu %xmm0, -16(%rsi, %rdi) + movdqa (%rsi), %xmm0 # load next string chunk + movdqa %xmm4, %xmm1 + sub $32, %rdx + jae 0b + +1: sub $16, %rsi # undo second advancement + add $16, %edx + + /* 1--16 bytes left in the buffer but string has not ended yet */ +2: pcmpeqb %xmm1, %xmm0 # NUL byte encountered? + pmovmskb %xmm0, %r8d + mov %r8d, %ecx + bts %edx, %r8d # treat end of buffer as end of string + or $0x10000, %eax # ensure TZCNT finds a set bit + tzcnt %r8d, %r8d # find tail length + add %rsi, %rdi # restore RDI + movdqu 1(%rsi, %r8, 1), %xmm0 # load string tail + movdqu %xmm0, 1(%rdi, %r8, 1) # store string tail + lea 17(%rdi, %r8, 1), %rsi # return value if terminator encountered + xor %eax, %eax # return value if no terminator encountered + bt %r8d, %ecx # terminator encountered inside buffer? + cmovc %rsi, %rax # if yes, return pointer, else NULL + ret + +4: sub $16, %rsi # undo second advancement + add $16, %rdx # restore number of remaining bytes + + /* string has ended but buffer has not */ +3: tzcnt %eax, %eax # find length of string tail + movdqu -15(%rsi, %rax, 1), %xmm0 # load string tail (incl. NUL) + add %rsi, %rdi # restore destination pointer + movdqu %xmm0, -15(%rdi, %rax, 1) # store string tail (incl. NUL) + lea 1(%rdi, %rax, 1), %rax # compute return value + ret + +.Lhead_buf_end: + pmovmskb %xmm1, %r8d + add $32, %edx # restore edx to (len-1) + ecx + shl $16, %r8d # place 2nd chunk NUL mask into bits 16--31 + mov %r8d, %r10d + bts %rdx, %r8 # treat end of buffer as if terminator present + xor %eax, %eax # return value if terminator not found + tzcnt %r8, %rdx # find string/buffer len from alignment boundary + lea 1(%rdi, %rdx, 1), %r8 # return value if terminator found + rcx + sub %rcx, %r8 # subtract rcx + bt %rdx, %r10 # was the terminator present? + cmovc %r8, %rax # if yes, return pointer, else NULL + sub %ecx, %edx # find actual string/buffer len + jmp .L0132 + +.Lsecond_nul: + add %r8, %rdx # restore buffer length + tzcnt %eax, %r8d # where is the NUL byte? + lea -16(%rcx), %eax + sub %eax, %r8d # string length + lea 1(%rdi, %r8, 1), %rax # return value if NUL before end of buffer + xor %ecx, %ecx # return value if not + cmp %r8, %rdx # is the string shorter than the buffer? + cmova %r8, %rdx # copy only min(buflen, srclen) bytes + cmovb %rcx, %rax # return NUL if buffer ended before string +.L0132: cmp $16, %rdx # at least 17 bytes to copy (not incl NUL)? + jb .L0116 + + /* copy 17--32 bytes */ + movdqu (%r9), %xmm0 # load first 16 bytes + movdqu -15(%r9, %rdx, 1), %xmm1 # load last 16 bytes + movdqu %xmm0, (%rdi) + movdqu %xmm1, -15(%rdi, %rdx, 1) + ret + +.Lhead_nul: + tzcnt %eax, %r8d # where is the NUL byte? + sub %ecx, %r8d # ... from the beginning of the string? + lea 1(%rdi, %r8, 1), %rax # return value if NUL before end of buffer + xor %ecx, %ecx # return value if not + cmp %r8, %rdx # is the string shorter than the buffer? + cmova %r8, %rdx # copy only min(buflen, srclen) bytes + cmovb %rcx, %rax # return NUL if buffer ended before string + + /* process strings of 1--16 bytes (rdx: min(buflen, srclen), rax: srclen) */ +.L0116: cmp $8, %rdx # at least 9 bytes to copy? + jae .L0916 + + cmp $4, %rdx # at least 5 bytes to copy? + jae .L0508 + + cmp $2, %rdx # at least 3 bytes to copy? + jae .L0304 + + /* copy one or two bytes */ + movzbl (%r9), %ecx # load first byte from src + movzbl (%r9, %rdx, 1), %esi # load last byte from src + mov %cl, (%rdi) # deposit into destination + mov %sil, (%rdi, %rdx, 1) + ret + +.L0304: movzwl (%r9), %ecx + movzwl -1(%r9, %rdx, 1), %esi + mov %cx, (%rdi) + mov %si, -1(%rdi, %rdx, 1) + ret + +.L0508: mov (%r9), %ecx + mov -3(%r9, %rdx, 1), %esi + mov %ecx, (%rdi) + mov %esi, -3(%rdi, %rdx, 1) + ret + +.L0916: mov (%r9), %rcx + mov -7(%r9, %rdx, 1), %rsi + mov %rcx, (%rdi) + mov %rsi, -7(%rdi, %rdx, 1) + ret + + /* length zero destination: return null pointer */ +.L0: xor %eax, %eax + ret +ARCHEND(__memccpy, baseline) + + .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/amd64/string/memrchr.S b/lib/libc/amd64/string/memrchr.S new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/memrchr.S @@ -0,0 +1,166 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Robert Clausecker + */ + +#include + +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4, 0x90 + +ARCHFUNCS(memrchr) + ARCHFUNC(memrchr, scalar) + ARCHFUNC(memrchr, baseline) +ENDARCHFUNCS(memrchr) + +ARCHENTRY(memrchr, scalar) + xor %eax, %eax # prospective return value + sub $4, %rdx # 4 bytes left to process? + jb 1f + + ALIGN_TEXT +0: xor %r8, %r8 + lea 2(%rdi), %r10 + cmp %sil, 2(%rdi) + cmovne %r8, %r10 # point to null if no match + + cmp %sil, (%rdi) + cmove %rdi, %r8 # point to first char if match + + lea 1(%rdi), %r9 + cmp %sil, 1(%rdi) + cmovne %r8, %r9 # point to first result if no match in second + + lea 3(%rdi), %r11 + cmp %sil, 3(%rdi) + cmovne %r10, %r11 + + test %r11, %r11 + cmovz %r9, %r11 # take first pair match if none in second + + test %r11, %r11 + cmovnz %r11, %rax # take match in current set if any + + add $4, %rdi + sub $4, %rdx + jae 0b + +1: cmp $-3, %edx # a least one character left to process? + jb 2f + + cmp %sil, (%rdi) + cmove %rdi, %rax + + lea 1(%rdi), %rcx + cmp $-2, %edx # at least two characters left to process? + jb 2f + + cmp %sil, 1(%rdi) + cmove %rcx, %rax + + lea 2(%rdi), %rcx + cmp $-1, %edx # at least three character left to process? + jb 2f + + cmp %sil, 2(%rdi) + cmove %rcx, %rax + +2: ret +ARCHEND(memrchr, scalar) + +ARCHENTRY(memrchr, baseline) + movd %esi, %xmm4 + test %rdx, %rdx # empty buffer? + jz .L0 # if yes, return immediately + + punpcklbw %xmm4, %xmm4 # c -> cc + mov %edi, %ecx + punpcklwd %xmm4, %xmm4 # cc -> cccc + and $~0xf, %rdi # align source pointer + pshufd $0, %xmm4, %xmm4 # cccc -> cccccccccccccccc + and $0xf, %ecx + movdqa %xmm4, %xmm0 + mov $-1, %r8d + pcmpeqb (%rdi), %xmm0 # compare aligned head + shl %cl, %r8d # mask of bytes in the head of the buffer + pmovmskb %xmm0, %eax + + sub $16, %rcx + and %r8d, %eax # match mask + add %rcx, %rdx # advance past head + cmc + jbe .Lrunt # did the string end in the buffer? + + mov %rdi, %rsi # pointer to matching chunk + add $16, %rdi + sub $16, %rdx # enough left for another round? + jbe 1f + + /* main loop unrolled twice */ + ALIGN_TEXT +0: movdqa %xmm4, %xmm0 + pcmpeqb (%rdi), %xmm0 + pmovmskb %xmm0, %r8d + + cmp $16, %rdx # enough left for second chunk? + jbe 2f + + movdqa %xmm4, %xmm0 + pcmpeqb 16(%rdi), %xmm0 + pmovmskb %xmm0, %ecx + + lea 16(%rdi), %r9 + test %ecx, %ecx # match found in second chunk? + cmovz %r8d, %ecx # if not, use match data from first chunk + cmovz %rdi, %r9 + + test %ecx, %ecx # any match found? + cmovnz %ecx, %eax # if yes, overwrite previously found match + cmovnz %r9, %rsi + + add $32, %rdi # advance to next iteration + sub $32, %rdx # advance to next chunks + ja 0b + + /* process remaining 1--16 bytes */ +1: pcmpeqb (%rdi), %xmm4 + mov $0xffff, %r8d + xor %ecx, %ecx + sub %edx, %ecx # number of bytes to be masked out + pmovmskb %xmm4, %r9d + shr %cl, %r8d # mask of bytes to be kept in the buffer + and %r9d, %r8d + cmovnz %r8d, %eax + cmovnz %rdi, %rsi + bsr %eax, %eax + lea (%rsi, %rax, 1), %rsi # pointer to match (or junk) + cmovnz %rsi, %rax # if any match was found, return it + ret + + /* end of chunk reached within first half iteration */ +2: test %r8d, %r8d # match in previous chunk? + cmovnz %r8d, %eax # if yes, overwrite previous chunks + cmovnz %rdi, %rsi + add $16, %rdi # point to tail + sub $16, %edx + jmp 1b # handle tail the same otherwise + + /* runt: string ends within head, edx has negated amount of invalid head bytes */ +.Lrunt: mov $0xffff, %r8d + xor %ecx, %ecx + sub %edx, %ecx + shr %cl, %r8d + and %r8d, %eax + bsr %eax, %eax + lea (%rdi, %rax, 1), %rdi + cmovnz %rdi, %rax + ret + + /* empty buffer: return a null pointer */ +.L0: xor %eax, %eax + ret +ARCHEND(memrchr, baseline) + + .section .note.GNU-stack, "", %progbits diff --git a/lib/libc/amd64/string/stpncpy.S b/lib/libc/amd64/string/stpncpy.S new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/stpncpy.S @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 + +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4, 0x90 + + .weak stpncpy + .set stpncpy, __stpncpy +ARCHFUNCS(__stpncpy) + ARCHFUNC(__stpncpy, scalar) + ARCHFUNC(__stpncpy, baseline) +ENDARCHFUNCS(__stpncpy) + +ARCHENTRY(__stpncpy, scalar) + push %rbp # establish stack frame + mov %rsp, %rbp + + push %rdx + push %rdi + push %rsi + push %rax # dummy push for alignment + + mov %rsi, %rdi + xor %esi, %esi + call CNAME(__memchr) # memchr(src, '\0', len) + pop %rcx # dummy pop + pop %rsi + mov -16(%rbp), %rdi + + test %rax, %rax # NUL found? + jz .Lfullcopy + + mov %rax, %rdx + sub %rsi, %rdx # copy until the NUL byte + add %rdx, -16(%rbp) # advance destination by string length + sub %rdx, -8(%rbp) # and shorten buffer size by string length + call CNAME(memcpy) + + pop %rdi + pop %rdx + xor %esi, %esi + pop %rbp + jmp CNAME(memset) # clear remaining buffer + +.Lfullcopy: + mov -8(%rbp), %rdx + call CNAME(memcpy) # copy whole string + add -8(%rbp), %rax # point to dest[n] + leave + ret +ARCHEND(__stpncpy, scalar) + + /* + * this mask allows us to generate masks of 16-n 0xff bytes + * followed by n 0x00 bytes by loading from .Lmask+n. + */ + .section .rodata +.Lmask: .quad 0xffffffffffffffff + .quad 0xffffffffffffffff + .quad 0x0000000000000000 + .quad 0x0000000000000000 + +/* stpncpy(char *restrict rdi, const char *rsi, size_t rdx) */ +ARCHENTRY(__stpncpy, baseline) +#define bounce (-3*16-8) /* location of on-stack bounce buffer */ + + test %rdx, %rdx # no bytes to copy? + jz .L0 + + mov %esi, %ecx + and $~0xf, %rsi # align source to 16 bytes + movdqa (%rsi), %xmm0 # load head + and $0xf, %ecx # offset from alignment + mov $-1, %r9d + lea -32(%rcx), %rax # set up overflow-proof comparison rdx+rcx<=32 + shl %cl, %r9d # mask of bytes belonging to the string + sub %rcx, %rdi # adjust RDI to correspond to RSI + pxor %xmm1, %xmm1 + movdqa %xmm0, bounce(%rsp) # stash copy of head on the stack + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %r8d + + lea (%rdx, %rcx, 1), %r10 # buffer length from alignment boundary + add %rdx, %rax # less than 2 chunks (32 bytes) to play with? + jnc .Lrunt # if yes, use special runt processing + + movdqu %xmm1, -16(%rdi, %r10, 1) # clear final bytes of destination + and %r9d, %r8d # end of string within head? + jnz .Lheadnul + + movdqu (%rsi, %rcx, 1), %xmm2 # load head from source buffer + movdqu %xmm2, (%rdi, %rcx, 1) # an deposit + + add $16, %rsi + add $16, %rdi + sub $32, %r10 + + /* main loop unrolled twice */ + ALIGN_TEXT +0: movdqa (%rsi), %xmm0 + pxor %xmm1, %xmm1 + pcmpeqb %xmm0, %xmm1 # NUL byte encountered? + pmovmskb %xmm1, %r8d + test %r8d, %r8d + jnz 3f + + movdqu %xmm0, (%rdi) + cmp $16, %r10 # more than a full chunk left? + jbe 1f + + movdqa 16(%rsi), %xmm0 + add $32, %rdi # advance pointers to next chunk + add $32, %rsi + pxor %xmm1, %xmm1 + pcmpeqb %xmm0, %xmm1 # NUL byte encountered? + pmovmskb %xmm1, %r8d + test %r8d, %r8d + jnz 2f + + movdqu %xmm0, -16(%rdi) + sub $32, %r10 # more than another full chunk left? + ja 0b + + sub $16, %rdi # undo second advancement + sub $16, %rsi + add $16, %r10d # restore number of remaining bytes + + /* 1--16 bytes left but string has not ended yet */ +1: pxor %xmm1, %xmm1 + pcmpeqb 16(%rsi), %xmm1 # NUL byte in source tail? + pmovmskb %xmm1, %r8d + bts %r10d, %r8d # treat end of buffer as NUL + tzcnt %r8d, %r8d # where is the NUL byte? + movdqu (%rsi, %r8, 1), %xmm0 # load source tail before NUL + lea 16(%rdi, %r8, 1), %rax # point return value to NUL byte + # or end of buffer + movdqu %xmm0, (%rdi, %r8, 1) # store tail into the buffer + ret + +2: sub $16, %rdi # undo second advancement + sub $16, %rsi + sub $16, %r10 + + /* string has ended and buffer has not */ +3: tzcnt %r8d, %r8d # where did the string end? + lea .Lmask+16(%rip), %rcx + lea (%rdi, %r8, 1), %rax # where the NUL byte will be + neg %r8 + movdqu (%rcx, %r8, 1), %xmm1 # mask with FF where the string is, + # 00 where it is not + pand %xmm1, %xmm0 # mask out bytes after the string + movdqu %xmm0, (%rdi) # store masked current chunk + pxor %xmm1, %xmm1 + sub $16, %r10 # another full chunk left? + jbe 1f + + /* clear remaining destination buffer (tail has been cleared earlier) */ + ALIGN_TEXT +0: movdqu %xmm1, 16(%rdi) + cmp $16, %r10 + jbe 1f + + movdqu %xmm1, 32(%rdi) + add $32, %rdi + sub $32, %r10 + ja 0b + +1: ret + + /* at least two chunks to play with and NUL while processing head */ +.Lheadnul: + movdqu bounce(%rsp, %rcx, 1), %xmm0 # load start of source from stack + tzcnt %r8d, %r8d # find location of NUL byte + movdqu %xmm0, (%rdi, %rcx, 1) # deposit head in the destination + movdqu %xmm1, (%rdi, %r8, 1) # clear out following bytes + movdqu %xmm1, 16(%rdi) # clear out second chunk + lea (%rdi, %r8, 1), %rax # make RAX point to the NUL byte + + add $32, %rdi # advance past first two chunks + sub $32+16, %r10 # advance past first three chunks + jbe 1f # did we pass the end of the buffer? + + /* clear remaining destination buffer (tail has been cleared earlier) */ + ALIGN_TEXT +0: movdqu %xmm1, (%rdi) # clear out buffer chunk + cmp $16, %r10 + jbe 1f + + movdqu %xmm1, 16(%rdi) + add $32, %rdi + sub $32, %r10 + ja 0b + +1: ret + + /* 1--32 bytes to copy, bounce through the stack */ +.Lrunt: movdqa %xmm1, bounce+16(%rsp) # clear out rest of on-stack copy + bts %r10d, %r8d # treat end of buffer as end of string + and %r9w, %r8w # end of string within first buffer? + jnz 0f # if yes, do not inspect second buffer + + movdqa 16(%rsi), %xmm0 # load second chunk of input + movdqa %xmm0, bounce+16(%rsp) # stash copy on stack + pcmpeqb %xmm1, %xmm0 # NUL in second chunk? + pmovmskb %xmm0, %r9d + shl $16, %r9d + or %r9d, %r8d # merge found NUL bytes into NUL mask + + /* end of string after one buffer */ +0: tzcnt %r8d, %r8d # location of last char in string + movdqu %xmm1, bounce(%rsp, %r8, 1) # clear bytes behind string + lea bounce(%rsp, %rcx, 1), %rsi # start of string copy on stack + lea (%rdi, %r8, 1), %rax # return pointer to NUL byte + + cmp $16, %edx # at least 16 bytes to transfer? + jae .L1631 + + mov (%rsi), %r8 # load string head + cmp $8, %edx # at least 8 bytes to transfer? + jae .L0815 + + cmp $4, %edx # at least 4 bytes to transfer? + jae .L0407 + + movzwl -2(%rsi, %rdx, 1), %esi # load last two bytes of string + mov %r8b, (%rdi, %rcx, 1) # store first byte + + cmp $2, %edx # at least 2 bytes to transfer? + jb .L1 + + mov %si, -2(%rdi, %r10, 1) # store last two bytes of string +.L1: ret + +.L1631: movdqu (%rsi), %xmm0 # load first 16 bytes of string + movdqu -16(%rsi, %rdx, 1), %xmm1 # load last 16 bytes of string + movdqu %xmm0, (%rdi, %rcx, 1) + movdqu %xmm1, -16(%rdi, %r10, 1) + ret + +.L0815: mov -8(%rsi, %rdx, 1), %rdx # load last 8 bytes of string + mov %r8, (%rdi, %rcx, 1) + mov %rdx, -8(%rdi, %r10, 1) + ret + +.L0407: mov -4(%rsi, %rdx, 1), %edx # load last four bytes of string + mov %r8d, (%rdi, %rcx, 1) + mov %edx, -4(%rdi, %r10, 1) + ret + + /* length 0 buffer: just return dest */ +.L0: mov %rdi, %rax + ret +ARCHEND(__stpncpy, baseline) + + .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/amd64/string/strcat.S b/lib/libc/amd64/string/strcat.S --- a/lib/libc/amd64/string/strcat.S +++ b/lib/libc/amd64/string/strcat.S @@ -1,6 +1,14 @@ -/* - * Written by J.T. Conklin - * Public domain. +/*- + * Copyright (c) 2023, The FreeBSD Foundation + * + * SPDX-License-Expression: BSD-2-Clause + * + * Portions of this software were developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * Adapted from NetBSD's common/lib/libc/arch/x86_64/string/strcat.S + * written by J.T. Conklin + * that was originally dedicated to the public domain */ #include @@ -8,7 +16,14 @@ RCSID("$NetBSD: strcat.S,v 1.4 2004/07/26 18:51:21 drochner Exp $") #endif -ENTRY(strcat) +#include "amd64_archlevel.h" + +ARCHFUNCS(strcat) + ARCHFUNC(strcat, scalar) + ARCHFUNC(strcat, baseline) +ENDARCHFUNCS(strcat) + +ARCHENTRY(strcat, scalar) movq %rdi,%rax movabsq $0x0101010101010101,%r8 movabsq $0x8080808080808080,%r9 @@ -161,6 +176,28 @@ .Ldone: ret -END(strcat) +ARCHEND(strcat, scalar) + +/* + * Call into strlen + strcpy if we have any SIMD at all. + * The scalar implementation above is better for the scalar + * case as it avoids the function call overhead, but pessimal + * if we could call SIMD routines instead. + */ +ARCHENTRY(strcat, baseline) + push %rbp + mov %rsp, %rbp + push %rsi + push %rbx + mov %rdi, %rbx # remember destination for later + call CNAME(strlen) # strlen(dest) + mov -8(%rbp), %rsi + lea (%rbx, %rax, 1), %rdi # dest + strlen(dest) + call CNAME(__stpcpy) # stpcpy(dest + strlen(dest), src) + mov %rbx, %rax # return dest + pop %rbx + leave + ret +ARCHEND(strcat, baseline) .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/amd64/string/strcmp.S b/lib/libc/amd64/string/strcmp.S --- a/lib/libc/amd64/string/strcmp.S +++ b/lib/libc/amd64/string/strcmp.S @@ -1,14 +1,33 @@ -/* - * Written by J.T. Conklin - * Public domain. +/*- + * Copyright (c) 2023, The FreeBSD Foundation + * + * SPDX-License-Expression: BSD-2-Clause + * + * Portions of this software were developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * Adapted from NetBSD's common/lib/libc/arch/x86_64/string/strcmp.S + * written by J.T. Conklin that was originally + * dedicated to the public domain. */ #include +#include + #if 0 RCSID("$NetBSD: strcmp.S,v 1.3 2004/07/19 20:04:41 drochner Exp $") #endif -ENTRY(strcmp) +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4, 0x90 + +ARCHFUNCS(strcmp) + ARCHFUNC(strcmp, scalar) + ARCHFUNC(strcmp, baseline) +ENDARCHFUNCS(strcmp) + +ARCHENTRY(strcmp, scalar) /* * Align s1 to word boundary. * Consider unrolling loop? @@ -39,7 +58,7 @@ movabsq $0x8080808080808080,%r9 subq $8,%rsi - .align 4 + ALIGN_TEXT .Lword_loop: movq 8(%rdi),%rax addq $8,%rdi @@ -53,7 +72,7 @@ testq %r9,%rdx je .Lword_loop - .align 4 + ALIGN_TEXT .Lbyte_loop: movb (%rdi),%al incq %rdi @@ -69,6 +88,272 @@ movzbq %dl,%rdx subq %rdx,%rax ret -END(strcmp) +ARCHEND(strcmp, scalar) + +ARCHENTRY(strcmp, baseline) + /* check if either string crosses a page in the head */ + lea 15(%rdi), %r8d # end of head + lea 15(%rsi), %r9d + mov %edi, %eax + mov %esi, %edx + xor %edi, %r8d # bits that changed between first and last byte + xor %esi, %r9d + and $~0xf, %rdi # align heads to 16 bytes + and $~0xf, %rsi + or %r8d, %r9d # in either RSI or RDI + and $0xf, %eax # offset from alignment + and $0xf, %edx + pxor %xmm1, %xmm1 + test $PAGE_SIZE, %r9d # did the page change? + jz 0f # if not, take fast path + + /* heads may cross page boundary, avoid unmapped loads */ + movdqa (%rdi), %xmm0 # load aligned heads + movdqa (%rsi), %xmm2 + mov $-1, %r8d + mov $-1, %r9d + mov %eax, %ecx + shl %cl, %r8d # string head in XMM0 + mov %edx, %ecx + shl %cl, %r9d # string head in XMM2 + movdqa %xmm0, -40(%rsp) # stash copies of the heads on the stack + movdqa %xmm2, -24(%rsp) + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm0, %r10d + pmovmskb %xmm2, %r11d + test %r8d, %r10d # NUL byte present in first string? + lea -40(%rsp), %r8 + cmovz %rdi, %r8 + test %r9d, %r11d # NUL byte present in second string? + lea -24(%rsp), %r9 + cmovz %rsi, %r9 + movdqu (%r8, %rax, 1), %xmm0 # load true (or fake) heads + movdqu (%r9, %rdx, 1), %xmm4 + jmp 1f + +0: movdqu (%rdi, %rax, 1), %xmm0 # load true heads + movdqu (%rsi, %rdx, 1), %xmm4 +1: pxor %xmm2, %xmm2 + pcmpeqb %xmm0, %xmm2 # NUL byte present? + pcmpeqb %xmm0, %xmm4 # which bytes match? + pandn %xmm4, %xmm2 # match and not NUL byte? + pmovmskb %xmm2, %r9d + xor $0xffff, %r9d # mismatch or NUL byte? + jnz .Lhead_mismatch + + /* load head and second chunk */ + movdqa 16(%rdi), %xmm2 # load second chunks + movdqa 16(%rsi), %xmm3 + sub %rdx, %rax # is a&0xf >= b&0xf? + jb .Lswapped # if not, proceed with swapped operands + + neg %rax + movdqu 16(%rsi, %rax, 1), %xmm0 + sub %rdi, %rsi # express RSI as distance from RDI + lea (%rsi, %rax, 1), %rdx # point RDX to offset in second string + neg %rax + pcmpeqb %xmm3, %xmm1 # ... corresponding to RDI + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add $16, %rdi + test %r8d, %r8d + jnz .Lnul_found + xor $0xffff, %r9d + jnz .Lmismatch + add $16, %rdi # advance aligned pointers + + /* + * During the main loop, the layout of the two strings is something like: + * + * v ------1------ v ------2------ v + * RDI: AAAAAAAAAAAAABBBBBBBBBBBBBBBB... + * RSI: AAAAAAAAAAAAABBBBBBBBBBBBBBBBCCC... + * + * where v indicates the alignment boundaries and corresponding chunks + * of the strings have the same letters. Chunk A has been checked in + * the previous iteration. This iteration, we first check that string + * RSI doesn't end within region 2, then we compare chunk B between the + * two strings. As RSI is known not to hold a NUL byte in regsions 1 + * and 2 at this point, this also ensures that RDI has not ended yet. + */ + ALIGN_TEXT +0: movdqu (%rdi, %rdx, 1), %xmm0 # chunk of 2nd string corresponding to RDI? + pxor %xmm1, %xmm1 + pcmpeqb (%rdi, %rsi, 1), %xmm1 # end of string in RSI? + pcmpeqb (%rdi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + test %r8d, %r8d + jnz .Lnul_found + xor $0xffff, %r9d # any mismatches? + jnz .Lmismatch + + /* main loop unrolled twice */ + movdqu 16(%rdi, %rdx, 1), %xmm0 # chunk of 2nd string corresponding to RDI? + pxor %xmm1, %xmm1 + pcmpeqb 16(%rdi, %rsi, 1), %xmm1 # end of string in RSI? + pcmpeqb 16(%rdi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add $32, %rdi + test %r8d, %r8d + jnz .Lnul_found2 + xor $0xffff, %r9d # any mismatches? + jz 0b + + sub $16, %rdi # roll back second increment + + /* a mismatch has been found between RDX and RSI */ +.Lmismatch: + tzcnt %r9d, %r9d # where is the mismatch? + add %rdi, %rdx # turn RDX from offset to pointer + movzbl (%rdx, %r9, 1), %ecx + movzbl (%rdi, %r9, 1), %eax + sub %ecx, %eax # difference of the mismatching chars + ret + + /* mismatch in true heads */ +.Lhead_mismatch: + tzcnt %r9d, %r9d # where is the mismatch? + add %rax, %rdi # return to true heads + add %rdx, %rsi + movzbl (%rdi, %r9, 1), %eax # mismatching characters + movzbl (%rsi, %r9, 1), %ecx + sub %ecx, %eax + ret + +.Lnul_found2: + sub $16, %rdi # roll back second increment + + /* a NUL has been found in RSI */ +.Lnul_found: + mov %eax, %ecx + mov %r8d, %r10d + shl %cl, %r8w # adjust NUL mask to positions in RDI/RDX + xor $0xffff, %r9d # mask of mismatches + or %r8d, %r9d # NUL bytes also count as mismatches + jnz .Lmismatch + + /* + * (RDI) == (RSI) and NUL is past the string. + * Compare (RSI) with the corresponding part + * of the other string until the NUL byte. + */ + movdqu (%rdi, %rax, 1), %xmm0 + pcmpeqb (%rdi, %rsi, 1), %xmm0 + add %rdi, %rsi # restore RSI pointer + add %rax, %rdi # point RDI to chunk corresponding to (RSI) + pmovmskb %xmm0, %ecx # mask of matches + not %ecx # mask of mismatches + or %r10d, %ecx # mask of mismatches or NUL bytes + tzcnt %ecx, %ecx # location of first mismatch + movzbl (%rdi, %rcx, 1), %eax + movzbl (%rsi, %rcx, 1), %ecx + sub %ecx, %eax + ret + + /* + * If (a&0xf) < (b&0xf), we do the same thing but with swapped + * operands. I found that this performs slightly better than + * using conditional moves to do the swap branchless. + */ +.Lswapped: + movdqu 16(%rdi, %rax, 1), %xmm0 + sub %rsi, %rdi # express RDI as distance from RSI + lea (%rdi, %rax, 1), %rdx # point RDX to offset in RDI corresponding to RSI + neg %rax # make difference positive + pcmpeqb %xmm2, %xmm1 + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add $16, %rsi # advance aligned pointers + test %r8d, %r8d + jnz .Lnul_founds + xor $0xffff, %r9d + jnz .Lmismatchs + add $16, %rsi + + /* + * During the main loop, the layout of the two strings is something like: + * + * v ------1------ v ------2------ v + * RDI: AAAAAAAAAAAAABBBBBBBBBBBBBBBB... + * RSI: AAAAAAAAAAAAABBBBBBBBBBBBBBBBCCC... + * + * where v indicates the alignment boundaries and corresponding chunks + * of the strings have the same letters. Chunk A has been checked in + * the previous iteration. This iteration, we first check that string + * RSI doesn't end within region 2, then we compare chunk B between the + * two strings. As RSI is known not to hold a NUL byte in regsions 1 + * and 2 at this point, this also ensures that RDI has not ended yet. + */ + ALIGN_TEXT +0: movdqu (%rsi, %rdx, 1), %xmm0 # chunk of 2nd string corresponding to RDI? + pxor %xmm1, %xmm1 + pcmpeqb (%rsi, %rdi, 1), %xmm1 # end of string in RSI? + pcmpeqb (%rsi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + test %r8d, %r8d + jnz .Lnul_founds + xor $0xffff, %r9d # any mismatches? + jnz .Lmismatchs + + /* main loop unrolled twice */ + movdqu 16(%rsi, %rdx, 1), %xmm0 # chunk of 2nd string corresponding to RDI? + pxor %xmm1, %xmm1 + pcmpeqb 16(%rsi, %rdi, 1), %xmm1 # end of string in RSI? + pcmpeqb 16(%rsi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add $32, %rsi + test %r8d, %r8d + jnz .Lnul_found2s + xor $0xffff, %r9d # any mismatches? + jz 0b + + sub $16, %rsi # roll back second increment + + /* a mismatch has been found between RDX and RDI */ +.Lmismatchs: + tzcnt %r9d, %r9d # where is the mismatch? + add %rsi, %rdx # turn RDX from offset to pointer + movzbl (%rdx, %r9, 1), %eax + movzbl (%rsi, %r9, 1), %ecx + sub %ecx, %eax # difference of the mismatching chars + ret + +.Lnul_found2s: + sub $16, %rsi # roll back second increment + + /* a NUL has been found in RSI */ +.Lnul_founds: + mov %eax, %ecx + mov %r8d, %r10d + shl %cl, %r8w # adjust NUL mask to positions in RDI/RDX + xor $0xffff, %r9d # mask of mismatches + or %r8d, %r9d # NUL bytes also count as mismatches + jnz .Lmismatchs + + /* + * (RDI) == (RSI) and NUL is past the string. + * Compare (RSI) with the corresponding part + * of the other string until the NUL byte. + */ + movdqu (%rsi, %rax, 1), %xmm0 + pcmpeqb (%rsi, %rdi, 1), %xmm0 + add %rsi, %rdi # restore RDI pointer + add %rax, %rsi # point RSI to chunk corresponding to (RDI) + pmovmskb %xmm0, %ecx # mask of matches + not %ecx # mask of mismatches + or %r10d, %ecx # mask of mismatches or NUL bytes + tzcnt %ecx, %ecx # location of first mismatch + movzbl (%rdi, %rcx, 1), %eax + movzbl (%rsi, %rcx, 1), %ecx + sub %ecx, %eax + ret +ARCHEND(strcmp, baseline) .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/amd64/string/strcspn.S b/lib/libc/amd64/string/strcspn.S --- a/lib/libc/amd64/string/strcspn.S +++ b/lib/libc/amd64/string/strcspn.S @@ -33,13 +33,15 @@ #define ALIGN_TEXT .p2align 4,0x90 /* 16-byte alignment, nop filled */ -ARCHFUNCS(strcspn) - ARCHFUNC(strcspn, scalar) + .weak strcspn + .set strcspn, __strcspn +ARCHFUNCS(__strcspn) + ARCHFUNC(__strcspn, scalar) NOARCHFUNC - ARCHFUNC(strcspn, x86_64_v2) -ENDARCHFUNCS(strcspn) + ARCHFUNC(__strcspn, x86_64_v2) +ENDARCHFUNCS(__strcspn) -ARCHENTRY(strcspn, scalar) +ARCHENTRY(__strcspn, scalar) push %rbp # align stack to enable function call mov %rsp, %rbp sub $256, %rsp # allocate space for lookup table @@ -122,7 +124,7 @@ sub (%rsp), %rax # length of prefix before match leave ret -ARCHEND(strcspn, scalar) +ARCHEND(__strcspn, scalar) /* * This kernel uses pcmpistri to do the heavy lifting. @@ -134,7 +136,7 @@ * 17--32: two pcmpistri per 16 bytes of input * >=33: fall back to look up table */ -ARCHENTRY(strcspn, x86_64_v2) +ARCHENTRY(__strcspn, x86_64_v2) push %rbp mov %rsp, %rbp sub $256, %rsp @@ -255,19 +257,28 @@ leave ret + /* match in first set half during head */ +.Lheadmatchv2first: + mov %ecx, %eax + pcmpistri $0, %xmm0, %xmm3 # match in second set half? + cmp %ecx, %eax # before the first half match? + cmova %ecx, %eax # use the earlier match + leave + ret + .Lgt16v2: movdqu 48(%rsp, %rcx, 1), %xmm3 # second part of set /* set is 17--32 bytes in size */ pcmpistri $0, %xmm0, %xmm2 # match in first set half? - jb .Lheadmatchv2 + jb .Lheadmatchv2first pcmpistri $0, %xmm0, %xmm3 # match in second set half or end of string? jbe .Lheadmatchv2 ALIGN_TEXT 0: movdqa (%rax), %xmm0 pcmpistri $0, %xmm0, %xmm2 - jb 2f # match in first set half? + jb 4f # match in first set half? pcmpistri $0, %xmm0, %xmm3 jbe 1f # match in second set half or end of string? movdqa 16(%rax), %xmm0 @@ -277,7 +288,8 @@ pcmpistri $0, %xmm0, %xmm3 ja 0b # neither match in 2nd half nor string end? -3: lea -16(%rax), %rax # go back to second half + /* match in second half or NUL */ + lea -16(%rax), %rax # go back to second half 1: jc 2f # jump if match found pxor %xmm1, %xmm1 pcmpeqb %xmm1, %xmm0 # where is the NUL byte? @@ -288,6 +300,17 @@ leave ret + /* match in first half */ +3: sub $16, %rax # go back to second half +4: sub %rdi, %rax # offset of %xmm0 from beginning of string + mov %ecx, %edx + pcmpistri $0, %xmm0, %xmm3 # match in second set half? + cmp %ecx, %edx # before the first half match? + cmova %ecx, %edx # use the earlier match + add %rdx, %rax # return full ofset + leave + ret + /* set is empty, degrades to strlen */ .Lstrlenv2: leave @@ -368,6 +391,6 @@ 2: sub %rdi, %rax # number of characters preceding match leave ret -ARCHEND(strcspn, x86_64_v2) +ARCHEND(__strcspn, x86_64_v2) .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/amd64/string/strlcat.c b/lib/libc/amd64/string/strlcat.c new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/strlcat.c @@ -0,0 +1,25 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Robert Clausecker + */ + +#include + +#include + +void *__memchr(const void *, int, size_t); +size_t __strlcpy(char *restrict, const char *restrict, size_t); + +size_t +strlcat(char *restrict dst, const char *restrict src, size_t dstsize) +{ + char *loc = __memchr(dst, '\0', dstsize); + + if (loc != NULL) { + size_t dstlen = (size_t)(loc - dst); + + return (dstlen + __strlcpy(loc, src, dstsize - dstlen)); + } else + return (dstsize + strlen(src)); +} diff --git a/lib/libc/amd64/string/strlcpy.S b/lib/libc/amd64/string/strlcpy.S new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/strlcpy.S @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 + +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4, 0x90 + + .weak strlcpy + .set strlcpy, __strlcpy +ARCHFUNCS(__strlcpy) + ARCHFUNC(__strlcpy, scalar) + ARCHFUNC(__strlcpy, baseline) +ENDARCHFUNCS(__strlcpy) + +ARCHENTRY(__strlcpy, scalar) + push %rbp # establish stack frame + mov %rsp, %rbp + push %rsi + push %rbx + push %rdi + push %rdx + mov %rsi, %rdi + call CNAME(strlen) # strlen(src) + pop %rdx + pop %rdi + mov -8(%rbp), %rsi + mov %rax, %rbx # remember string length for return value + sub $1, %rdx # do not copy into the final byte of the buffer + jc 0f # skip copying altogether if buffer was empty + cmp %rax, %rdx # is the buffer longer than the input? + cmova %rax, %rdx # if yes, only copy the part that fits + movb $0, (%rdi, %rdx, 1) # NUL-terminate output buffer + call CNAME(memcpy) # copy string to output +0: mov %rbx, %rax # restore return value + pop %rbx + leave + ret +ARCHEND(__strlcpy, scalar) + +ARCHENTRY(__strlcpy, baseline) + sub $1, %rdx # do not count NUL byte in buffer length + jb .L0 # go to special code path if len was 0 + + mov %esi, %ecx + pxor %xmm1, %xmm1 + mov %rsi, %r9 # stash a copy of the source pointer for later + and $~0xf, %rsi + pcmpeqb (%rsi), %xmm1 # NUL found in head? + mov $-1, %r8d + and $0xf, %ecx + shl %cl, %r8d # mask of bytes in the string + pmovmskb %xmm1, %eax + and %r8d, %eax + jnz .Lhead_nul + + movdqa 16(%rsi), %xmm3 # load second string chunk + movdqu (%r9), %xmm2 # load unaligned string head + mov $32, %r8d + sub %ecx, %r8d # head length + length of second chunk + pxor %xmm1, %xmm1 + pcmpeqb %xmm3, %xmm1 # NUL found in second chunk? + + sub %r8, %rdx # enough space left for the second chunk? + jbe .Lhead_buf_end + + /* process second chunk */ + pmovmskb %xmm1, %eax + test %eax, %eax + jnz .Lsecond_nul + + /* string didn't end in second chunk and neither did buffer -- not a runt! */ + movdqa 32(%rsi), %xmm0 # load next string chunk + pxor %xmm1, %xmm1 + movdqu %xmm2, (%rdi) # deposit head into buffer + sub %rcx, %rdi # adjust RDI to correspond to RSI + movdqu %xmm3, 16(%rdi) # deposit second chunk + sub %rsi, %rdi # express RDI as distance from RSI + add $32, %rsi # advance RSI past first two chunks + sub $16, %rdx # enough left for another round? + jbe 1f + + /* main loop unrolled twice */ + ALIGN_TEXT +0: pcmpeqb %xmm0, %xmm1 # NUL byte encountered? + pmovmskb %xmm1, %eax + test %eax, %eax + jnz 3f + + movdqu %xmm0, (%rsi, %rdi) + movdqa 16(%rsi), %xmm0 # load next string chunk + pxor %xmm1, %xmm1 + cmp $16, %rdx # more than a full chunk left? + jbe 2f + + add $32, %rsi # advance pointers to next chunk + pcmpeqb %xmm0, %xmm1 # NUL byte encountered? + pmovmskb %xmm1, %eax + test %eax, %eax + jnz 4f + + movdqu %xmm0, -16(%rsi, %rdi) + movdqa (%rsi), %xmm0 # load next string chunk + pxor %xmm1, %xmm1 + sub $32, %rdx + ja 0b + +1: sub $16, %rsi # undo second advancement + add $16, %edx + + /* 1--16 bytes left in the buffer but string has not ended yet */ +2: pcmpeqb %xmm1, %xmm0 # NUL byte encountered? + pmovmskb %xmm0, %r8d + mov %r8d, %eax + bts %edx, %r8d # treat end of buffer as end of string + tzcnt %r8d, %r8d # find tail length + add %rsi, %rdi # restore RDI + movdqu (%rsi, %r8, 1), %xmm0 # load string tail + movdqu %xmm0, (%rdi, %r8, 1) # store string tail + movb $0, 16(%rdi, %r8, 1) # NUL terminate + + /* continue to find the end of the string */ + test %eax, %eax # end of string already reached? + jnz 1f + + ALIGN_TEXT +0: pcmpeqb 32(%rsi), %xmm1 + pmovmskb %xmm1, %eax + pxor %xmm1, %xmm1 + test %eax, %eax + jnz 2f + + pcmpeqb 48(%rsi), %xmm1 + pmovmskb %xmm1, %eax + add $32, %rsi + pxor %xmm1, %xmm1 + test %eax, %eax + jz 0b + +1: sub $16, %rsi # undo second advancement +2: tzcnt %eax, %eax # where is the NUL byte? + sub %r9, %rsi + lea 32(%rsi, %rax, 1), %rax # return string length + ret + +4: sub $16, %rsi # undo second advancement + add $16, %rdx # restore number of remaining bytes + + /* string has ended but buffer has not */ +3: tzcnt %eax, %eax # find length of string tail + movdqu -15(%rsi, %rax, 1), %xmm0 # load string tail (incl. NUL) + add %rsi, %rdi # restore destination pointer + movdqu %xmm0, -15(%rdi, %rax, 1) # store string tail (incl. NUL) + sub %r9, %rsi # string length to current chunk + add %rsi, %rax # plus length of current chunk + ret + +.Lhead_buf_end: + pmovmskb %xmm1, %r8d + add $32, %edx # restore edx to (len-1) + ecx + mov %r8d, %eax + shl $16, %r8d # place 2nd chunk NUL mask into bits 16--31 + bts %rdx, %r8 # treat end of buffer as end of string + tzcnt %r8, %rdx # find string/bufer len from alignment boundary + sub %ecx, %edx # find actual string/buffer len + movb $0, (%rdi, %rdx, 1) # write NUL terminator + + /* continue to find the end of the string */ + test %eax, %eax # end of string already reached? + jnz 1f + + ALIGN_TEXT +0: pcmpeqb 32(%rsi), %xmm1 + pmovmskb %xmm1, %eax + pxor %xmm1, %xmm1 + test %eax, %eax + jnz 2f + + pcmpeqb 48(%rsi), %xmm1 + pmovmskb %xmm1, %eax + add $32, %rsi + pxor %xmm1, %xmm1 + test %eax, %eax + jz 0b + +1: sub $16, %rsi +2: tzcnt %eax, %eax + sub %r9, %rsi + lea 32(%rsi, %rax, 1), %rax # return string length + jmp .L0031 + +.Lsecond_nul: + add %r8, %rdx # restore buffer length + tzcnt %eax, %eax # where is the NUL byte? + lea -16(%rcx), %r8d + sub %r8d, %eax # string length + cmp %rax, %rdx # is the string shorter than the buffer? + cmova %rax, %rdx # copy only min(buflen, srclen) bytes + movb $0, (%rdi, %rdx, 1) # write NUL terminator +.L0031: cmp $16, %rdx # at least 16 bytes to copy (not incl NUL)? + jb .L0015 + + /* copy 16--31 bytes */ + movdqu (%r9), %xmm0 # load first 16 bytes + movdqu -16(%r9, %rdx, 1), %xmm1 # load last 16 bytes + movdqu %xmm0, (%rdi) + movdqu %xmm1, -16(%rdi, %rdx, 1) + ret + +.Lhead_nul: + tzcnt %eax, %eax # where is the NUL byte? + sub %ecx, %eax # ... from the beginning of the string? + cmp %rax, %rdx # is the string shorter than the buffer? + cmova %rax, %rdx # copy only min(buflen, srclen) bytes + movb $0, (%rdi, %rdx, 1) # write NUL terminator + + /* process strings of 0--15 bytes (rdx: min(buflen, srclen), rax: srclen) */ +.L0015: cmp $8, %rdx # at least 8 bytes to copy? + jae .L0815 + + cmp $4, %rdx # at least 4 bytes to copy? + jae .L0407 + + cmp $2, %rdx # at least 2 bytes to copy? + jae .L0203 + + movzbl (%r9), %ecx # load first byte from src + mov %cl, (%rdi) # deposit into destination + movb $0, (%rdi, %rdx, 1) # add NUL terminator (again) + ret + +.L0203: movzwl (%r9), %ecx + movzwl -2(%r9, %rdx, 1), %esi + mov %cx, (%rdi) + mov %si, -2(%rdi, %rdx, 1) + ret + +.L0407: mov (%r9), %ecx + mov -4(%r9, %rdx, 1), %esi + mov %ecx, (%rdi) + mov %esi, -4(%rdi, %rdx, 1) + ret + +.L0815: mov (%r9), %rcx + mov -8(%r9, %rdx, 1), %rsi + mov %rcx, (%rdi) + mov %rsi, -8(%rdi, %rdx, 1) + ret + + /* length zero destination: just return the string length */ +.L0: mov %rsi, %rdi + jmp CNAME(strlen) +ARCHEND(__strlcpy, baseline) + + .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/amd64/string/strncat.c b/lib/libc/amd64/string/strncat.c new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/strncat.c @@ -0,0 +1,29 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Robert Clausecker + */ + +#include + +#include + +void *__memccpy(void *restrict, const void *restrict, int, size_t); + +char * +strncat(char *dest, const char *src, size_t n) +{ + size_t len; + char *endptr; + + len = strlen(dest); + endptr = __memccpy(dest + len, src, '\0', n); + + /* avoid an extra branch */ + if (endptr == NULL) + endptr = dest + len + n + 1; + + endptr[-1] = '\0'; + + return (dest); +} diff --git a/lib/libc/amd64/string/strncmp.S b/lib/libc/amd64/string/strncmp.S new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/strncmp.S @@ -0,0 +1,488 @@ +/*- + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 +#include + +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4, 0x90 + +ARCHFUNCS(strncmp) + ARCHFUNC(strncmp, scalar) + ARCHFUNC(strncmp, baseline) +ENDARCHFUNCS(strncmp) + +/* + * This is just the scalar loop unrolled a bunch of times. + */ +ARCHENTRY(strncmp, scalar) + xor %eax, %eax + sub $4, %rdx # 4 chars left to compare? + jbe 1f + + ALIGN_TEXT +0: movzbl (%rdi), %ecx + test %ecx, %ecx # NUL char in first string? + jz .L0 + cmpb (%rsi), %cl # mismatch between strings? + jnz .L0 + + movzbl 1(%rdi), %ecx + test %ecx, %ecx + jz .L1 + cmpb 1(%rsi), %cl + jnz .L1 + + movzbl 2(%rdi), %ecx + test %ecx, %ecx + jz .L2 + cmpb 2(%rsi), %cl + jnz .L2 + + movzbl 3(%rdi), %ecx + test %ecx, %ecx + jz .L3 + cmpb 3(%rsi), %cl + jnz .L3 + + add $4, %rdi # advance to next iteration + add $4, %rsi + sub $4, %rdx + ja 0b + + /* end of string within the next 4 characters */ +1: cmp $-4, %edx # end of string reached immediately? + jz .Leq + movzbl (%rdi), %ecx + test %ecx, %ecx + jz .L0 + cmpb (%rsi), %cl + jnz .L0 + + cmp $-3, %edx # end of string reached after 1 char? + jz .Leq + movzbl 1(%rdi), %ecx + test %ecx, %ecx + jz .L1 + cmpb 1(%rsi), %cl + jnz .L1 + + cmp $-2, %edx + jz .Leq + movzbl 2(%rdi), %ecx + test %ecx, %ecx + jz .L2 + cmpb 2(%rsi), %cl + jnz .L2 + + cmp $-1, %edx # either end of string after 3 chars, + jz .Leq # or it boils down to the last char + +.L3: inc %eax +.L2: inc %eax +.L1: inc %eax +.L0: movzbl (%rsi, %rax, 1), %ecx + movzbl (%rdi, %rax, 1), %eax + sub %ecx, %eax +.Leq: ret +ARCHEND(strncmp, scalar) + +ARCHENTRY(strncmp, baseline) + push %rbx + sub $1, %rdx # RDX--, so RDX points to the last byte to compare + jb .Lempty # where there any bytes to compare at all? + + lea 15(%rdi), %r8d # end of head + lea 15(%rsi), %r9d + mov %edi, %eax + mov %esi, %ebx + xor %edi, %r8d # bits that changed between first and last byte + xor %esi, %r9d + and $~0xf, %rdi # align heads to 16 bytes + and $~0xf, %rsi + or %r8d, %r9d + and $0xf, %eax # offset from alignment + and $0xf, %ebx + movdqa (%rdi), %xmm0 # load aligned heads + movdqa (%rsi), %xmm2 + pxor %xmm1, %xmm1 + cmp $16, %rdx # end of buffer within the first 32 bytes? + jb .Llt16 + + test $PAGE_SIZE, %r9d # did the page change? + jz 0f # if not, take fast path + + + /* heads may cross page boundary, avoid unmapped loads */ + movdqa %xmm0, -32(%rsp) # stash copies of the heads on the stack + movdqa %xmm2, -16(%rsp) + mov $-1, %r8d + mov $-1, %r9d + mov %eax, %ecx + shl %cl, %r8d # string head in XMM0 + mov %ebx, %ecx + shl %cl, %r9d # string head in XMM2 + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm0, %r10d + pmovmskb %xmm2, %r11d + test %r8d, %r10d # NUL byte present in first string? + lea -32(%rsp), %r8 + cmovz %rdi, %r8 + test %r9d, %r11d # NUL byte present in second string? + lea -16(%rsp), %r9 + cmovz %rsi, %r9 + movdqu (%r8, %rax, 1), %xmm0 # load true (or fake) heads + movdqu (%r9, %rbx, 1), %xmm4 + jmp 1f + + /* rdx == 0 */ +.Lempty: + xor %eax, %eax # zero-length buffers compare equal + pop %rbx + ret + +0: movdqu (%rdi, %rax, 1), %xmm0 # load true heads + movdqu (%rsi, %rbx, 1), %xmm4 +1: pxor %xmm2, %xmm2 + pcmpeqb %xmm0, %xmm2 # NUL byte present? + pcmpeqb %xmm0, %xmm4 # which bytes match? + pandn %xmm4, %xmm2 # match and not NUL byte? + pmovmskb %xmm2, %r9d + xor $0xffff, %r9d # mismatch or NUL byte? + jnz .Lhead_mismatch + + /* load head and second chunk */ + movdqa 16(%rdi), %xmm2 # load second chunks + movdqa 16(%rsi), %xmm3 + lea -16(%rdx, %rbx, 1), %rdx # account for length of RSI chunk + sub %rbx, %rax # is a&0xf >= b&0xf? + jb .Lswapped # if not, proceed with swapped operands + jmp .Lnormal + + /* buffer ends within the first 16 bytes */ +.Llt16: test $PAGE_SIZE, %r9d # did the page change? + jz 0f # if not, take fast path + + /* heads may cross page boundary */ + movdqa %xmm0, -32(%rsp) # stash copies of the heads on the stack + movdqa %xmm2, -16(%rsp) + mov $-1, %r8d + mov $-1, %r9d + mov %eax, %ecx + shl %cl, %r8d # string head in XMM0 + mov %ebx, %ecx + shl %cl, %r9d # string head in XMM2 + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm0, %r10d + pmovmskb %xmm2, %r11d + lea (%rdx, %rax, 1), %ecx # location of last buffer byte in xmm0 + bts %ecx, %r10d # treat as if NUL byte present + lea (%rdx, %rbx, 1), %ecx + bts %ecx, %r11d + test %r8w, %r10w # NUL byte present in first string head? + lea -32(%rsp), %r8 + cmovz %rdi, %r8 + test %r9w, %r11w # NUL byte present in second string head? + lea -16(%rsp), %r9 + cmovz %rsi, %r9 + movdqu (%r8, %rax, 1), %xmm0 # load true (or fake) heads + movdqu (%r9, %rbx, 1), %xmm4 + jmp 1f + +0: movdqu (%rdi, %rax, 1), %xmm0 # load true heads + movdqu (%rsi, %rbx, 1), %xmm4 +1: pxor %xmm2, %xmm2 + pcmpeqb %xmm0, %xmm2 # NUL byte present? + pcmpeqb %xmm0, %xmm4 # which bytes match? + pandn %xmm4, %xmm2 # match and not NUL byte? + pmovmskb %xmm2, %r9d + btr %edx, %r9d # induce mismatch in last byte of buffer + not %r9d # mismatch or NUL byte? + + /* mismatch in true heads */ + ALIGN_TEXT +.Lhead_mismatch: + tzcnt %r9d, %r9d # where is the mismatch? + add %rax, %rdi # return to true heads + add %rbx, %rsi + movzbl (%rdi, %r9, 1), %eax # mismatching characters + movzbl (%rsi, %r9, 1), %ecx + sub %ecx, %eax + pop %rbx + ret + + /* rax >= 0 */ + ALIGN_TEXT +.Lnormal: + neg %rax + movdqu 16(%rsi, %rax, 1), %xmm0 + sub %rdi, %rsi # express RSI as distance from RDI + lea (%rsi, %rax, 1), %rbx # point RBX to offset in second string + neg %rax # ... corresponding to RDI + pcmpeqb %xmm3, %xmm1 # NUL present? + pcmpeqb %xmm2, %xmm0 # Mismatch between chunks? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + mov $16, %ecx + cmp %rcx, %rdx # does the buffer end within (RDI,RSI,1)? + cmovb %edx, %ecx # ECX = min(16, RDX) + add $32, %rdi # advance to next iteration + bts %ecx, %r8d # mark end-of-buffer as if there was a NUL byte + test %r8w, %r8w # NUL or end of buffer found? + jnz .Lnul_found2 + xor $0xffff, %r9d + jnz .Lmismatch2 + sub $48, %rdx # end of buffer within first main loop iteration? + jb .Ltail # if yes, process tail + + /* + * During the main loop, the layout of the two strings is something like: + * + * v ------1------ v ------2------ v + * RDI: AAAAAAAAAAAAABBBBBBBBBBBBBBBB... + * RSI: AAAAAAAAAAAAABBBBBBBBBBBBBBBBCCC... + * + * where v indicates the alignment boundaries and corresponding chunks + * of the strings have the same letters. Chunk A has been checked in + * the previous iteration. This iteration, we first check that string + * RSI doesn't end within region 2, then we compare chunk B between the + * two strings. As RSI is known not to hold a NUL byte in regsions 1 + * and 2 at this point, this also ensures that RDI has not ended yet. + */ + ALIGN_TEXT +0: movdqu (%rdi, %rbx, 1), %xmm0 # chunk of 2nd string corresponding to RDI + pxor %xmm1, %xmm1 + pcmpeqb (%rdi, %rsi, 1), %xmm1 # end of string in RSI? + pcmpeqb (%rdi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + test %r8d, %r8d + jnz .Lnul_found + xor $0xffff, %r9d # any mismatches? + jnz .Lmismatch + + /* main loop unrolled twice */ + movdqu 16(%rdi, %rbx, 1), %xmm0 + pxor %xmm1, %xmm1 + pcmpeqb 16(%rdi, %rsi, 1), %xmm1 + pcmpeqb 16(%rdi), %xmm0 + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add $32, %rdi + test %r8d, %r8d + jnz .Lnul_found2 + xor $0xffff, %r9d + jnz .Lmismatch2 + sub $32, %rdx # end of buffer within next iteration? + jae 0b + + /* end of buffer will occur in next 32 bytes */ +.Ltail: movdqu (%rdi, %rbx, 1), %xmm0 # chunk of 2nd string corresponding to RDI + pxor %xmm1, %xmm1 + pcmpeqb (%rdi, %rsi, 1), %xmm1 # end of string in RSI? + pcmpeqb (%rdi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + bts %edx, %r8d # indicate NUL byte at last byte in buffer + test %r8w, %r8w # NUL byte in first chunk? + jnz .Lnul_found + xor $0xffff, %r9d # any mismatches? + jnz .Lmismatch + + /* main loop unrolled twice */ + movdqu 16(%rdi, %rbx, 1), %xmm0 + pxor %xmm1, %xmm1 + pcmpeqb 16(%rdi, %rsi, 1), %xmm1 + pcmpeqb 16(%rdi), %xmm0 + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + sub $16, %edx # take first half into account + bts %edx, %r8d # indicate NUL byte at last byte in buffer + add $32, %rdi + +.Lnul_found2: + sub $16, %rdi + +.Lnul_found: + mov %eax, %ecx + mov %r8d, %r10d + shl %cl, %r8d # adjust NUL mask to positions in RDI/RBX + not %r9d # mask of mismatches + or %r8w, %r9w # NUL bytes als count as mismatches + jnz .Lmismatch + + /* + * (RDI) == (RSI) and NUL is past the string. + * compare (RSI) with the corresponding part + * of the other string until the NUL byte. + */ + movdqu (%rdi, %rax, 1), %xmm0 + pcmpeqb (%rdi, %rsi, 1), %xmm0 + add %rdi, %rsi # restore RSI pointer + add %rax, %rdi # point RDI to chunk corresponding to (RSI) + pmovmskb %xmm0, %ecx # mask of matches + not %ecx # mask of mismatches + or %r10d, %ecx # mask of mismatches or NUL bytes + tzcnt %ecx, %ecx # location of first mismatch + movzbl (%rdi, %rcx, 1), %eax + movzbl (%rsi, %rcx, 1), %ecx + sub %ecx, %eax + pop %rbx + ret + +.Lmismatch2: + sub $16, %rdi + + /* a mismatch has been found between RBX and RSI */ +.Lmismatch: + tzcnt %r9d, %r9d # where is the mismatch? + add %rdi, %rbx # turn RBX from offset into pointer + movzbl (%rbx, %r9, 1), %ecx + movzbl (%rdi, %r9, 1), %eax + sub %ecx, %eax + pop %rbx + ret + + /* rax < 0 */ + ALIGN_TEXT +.Lswapped: + movdqu 16(%rdi, %rax, 1), %xmm0 + sub %rsi, %rdi # express RDI as distance from RDI + lea (%rdi, %rax, 1), %rbx # point RBX to offset in first string + pcmpeqb %xmm2, %xmm1 # NUL present? + pcmpeqb %xmm3, %xmm0 # mismatch between chunks? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add %rax, %rdx # RDX points to buffer end in RSI + neg %rax # ... corresponding to RSI + mov $16, %ecx + cmp %rcx, %rdx # does the buffer end within (RSI,RDI,1)? + cmovb %edx, %ecx # ECX = min(16, RDX) + add $32, %rsi + bts %ecx, %r8d # mark end-of-buffer as if there was a NUL byte + test %r8w, %r8w # NUL or end of buffer found? + jnz .Lnul_found2s + xor $0xffff, %r9d + jnz .Lmismatch2s + sub $48, %rdx # end of buffer within first main loop iteration? + jb .Ltails # if yes, process tail + + ALIGN_TEXT +0: movdqu (%rsi, %rbx, 1), %xmm0 # chunk of 1st string corresponding to RSI + pxor %xmm1, %xmm1 + pcmpeqb (%rsi, %rdi, 1), %xmm1 # end of string in RDI? + pcmpeqb (%rsi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + test %r8d, %r8d + jnz .Lnul_founds + xor $0xffff, %r9d # any mismatches? + jnz .Lmismatchs + + /* main loop unrolled twice */ + movdqu 16(%rsi, %rbx, 1), %xmm0 + pxor %xmm1, %xmm1 + pcmpeqb 16(%rsi, %rdi, 1), %xmm1 + pcmpeqb 16(%rsi), %xmm0 + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + add $32, %rsi + test %r8d, %r8d + jnz .Lnul_found2s + xor $0xffff, %r9d + jnz .Lmismatch2s + sub $32, %rdx # end of buffer within next iteration? + jae 0b + + /* end of buffer will occur in next 32 bytes */ +.Ltails: + movdqu (%rsi, %rbx, 1), %xmm0 # chunk of 1st string corresponding to RSI + pxor %xmm1, %xmm1 + pcmpeqb (%rsi, %rdi, 1), %xmm1 # end of string in RDI? + pcmpeqb (%rsi), %xmm0 # where do the chunks match? + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + bts %edx, %r8d # indicate NUL byte at laste byte in buffer + test %r8w, %r8w # NUL byte in first chunk? + jnz .Lnul_founds + xor $0xffff, %r9d # any mismatches? + jnz .Lmismatchs + + /* main loop unrolled twice */ + movdqu 16(%rsi, %rbx, 1), %xmm0 + pxor %xmm1, %xmm1 + pcmpeqb 16(%rsi, %rdi, 1), %xmm1 + pcmpeqb 16(%rsi), %xmm0 + pmovmskb %xmm1, %r8d + pmovmskb %xmm0, %r9d + sub $16, %edx # take first half into account + bts %edx, %r8d # indicate NUL byte at laste byte in buffer + add $32, %rsi + +.Lnul_found2s: + sub $16, %rsi + +.Lnul_founds: + mov %eax, %ecx + mov %r8d, %r10d + shl %cl, %r8d # adjust NUL mask to positions in RSI/RBX + not %r9d # mask of mismatches + or %r8w, %r9w # NUL bytes also count as mismatches + jnz .Lmismatchs + + movdqu (%rsi, %rax, 1), %xmm0 + pcmpeqb (%rsi, %rdi, 1), %xmm0 + add %rsi, %rdi # restore RDI pointer + add %rax, %rsi # point RSI to chunk corresponding to (RDI) + pmovmskb %xmm0, %ecx # mask of matches + not %ecx # mask of mismatches + or %r10d, %ecx # mask of mismatches or NUL bytes + tzcnt %ecx, %ecx # location of first mismatch + movzbl (%rdi, %rcx, 1), %eax + movzbl (%rsi, %rcx, 1), %ecx + sub %ecx, %eax + pop %rbx + ret + +.Lmismatch2s: + sub $16, %rsi + +.Lmismatchs: + tzcnt %r9d, %r9d # where is the mismatch? + add %rsi, %rbx # turn RBX from offset into pointer + movzbl (%rbx, %r9, 1), %eax + movzbl (%rsi, %r9, 1), %ecx + sub %ecx, %eax + pop %rbx + ret +ARCHEND(strncmp, baseline) + + .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/string/memccpy.c b/lib/libc/amd64/string/strncpy.c copy from lib/libc/string/memccpy.c copy to lib/libc/amd64/string/strncpy.c --- a/lib/libc/string/memccpy.c +++ b/lib/libc/amd64/string/strncpy.c @@ -1,8 +1,8 @@ /*- - * SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2023 The FreeBSD Foundation * - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,37 +12,30 @@ * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * 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 REGENTS OR CONTRIBUTORS BE LIABLE + * 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. + * SUCH DAMAGE */ +#include #include -void * -memccpy(void *t, const void *f, int c, size_t n) +char *__stpncpy(char *restrict, const char *restrict, size_t); + +char * +strncpy(char *restrict dst, const char *restrict src, size_t len) { - if (n) { - unsigned char *tp = t; - const unsigned char *fp = f; - unsigned char uc = c; - do { - if ((*tp++ = *fp++) == uc) - return (tp); - } while (--n != 0); - } - return (0); + __stpncpy(dst, src, len); + + return (dst); } diff --git a/lib/libc/string/memccpy.c b/lib/libc/amd64/string/strpbrk.c copy from lib/libc/string/memccpy.c copy to lib/libc/amd64/string/strpbrk.c --- a/lib/libc/string/memccpy.c +++ b/lib/libc/amd64/string/strpbrk.c @@ -1,8 +1,8 @@ /*- - * SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2023 The FreeBSD Foundation * - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,37 +12,32 @@ * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * 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 REGENTS OR CONTRIBUTORS BE LIABLE + * 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. + * SUCH DAMAGE */ +#include + #include -void * -memccpy(void *t, const void *f, int c, size_t n) +size_t __strcspn(const char *, const char *); + +char * +strpbrk(const char *s, const char *charset) { + size_t loc; + + loc = __strcspn(s, charset); - if (n) { - unsigned char *tp = t; - const unsigned char *fp = f; - unsigned char uc = c; - do { - if ((*tp++ = *fp++) == uc) - return (tp); - } while (--n != 0); - } - return (0); + return (s[loc] == '\0' ? NULL : (char *)&s[loc]); } diff --git a/lib/libc/amd64/string/strrchr.S b/lib/libc/amd64/string/strrchr.S new file mode 100644 --- /dev/null +++ b/lib/libc/amd64/string/strrchr.S @@ -0,0 +1,209 @@ +/*- + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 + +#include "amd64_archlevel.h" + +#define ALIGN_TEXT .p2align 4,0x90 # 16-byte alignment, nop-filled + + .weak rindex + .set rindex, strrchr + +ARCHFUNCS(strrchr) + ARCHFUNC(strrchr, scalar) + ARCHFUNC(strrchr, baseline) +ENDARCHFUNCS(strrchr) + +ARCHENTRY(strrchr, scalar) + mov %edi, %ecx + and $~7, %rdi # align to 8 byte + movzbl %sil, %esi # clear stray high bits + movabs $0x0101010101010101, %r8 + mov (%rdi), %rax # load first word + imul %r8, %rsi # replicate char 8 times + + /* + * Unaligned input: align to 8 bytes. Then proceed the same + * way as with aligned input, but prevent matches before the + * beginning of the string. This is achieved by oring 0x01 + * into each byte of the buffer before the string + */ + shl $3, %ecx + mov %r8, %r10 + shl %cl, %r10 # 0x01 where the string is + xor %r8, %r10 # 0x01 where it is not + neg %r8 # negate 01..01 so we can use lea + movabs $0x8080808080808080, %r9 + + mov %rsi, %rcx + xor %rax, %rcx # str ^ c + or %r10, %rax # ensure str != 0 before string + or %r10, %rcx # ensure str^c != 0 before string + bswap %rcx # in reverse order, to find last match + mov %rdi, %r10 # location of initial mismatch (if any) + xor %r11, %r11 # initial mismatch (none) + add $8, %rdi # advance to next iteration + lea (%rax, %r8, 1), %rdx # str - 0x01..01 + not %rax # ~str + and %rdx, %rax # (str - 0x01..01) & ~str + and %r9, %rax # not including junk bits + jnz 1f # end of string? + + lea (%rcx, %r8, 1), %rdx # (str ^ c) - 0x01..01 + not %rcx # ~(str ^ c) + and %rdx, %rcx # ((str ^ c - 0x01..01) & ~(str ^ c) + and %r9, %rcx # not including junk bits + mov %rcx, %r11 # remember mismatch in head + jmp 0f + + /* main loop unrolled twice */ + ALIGN_TEXT +3: lea (%rcx, %r8, 1), %rdx # (str ^ c) - 0x01..01 + not %rcx # ~(str ^ c) + and %rdx, %rcx # ((str ^ c - 0x01..01) & ~(str ^ c) + and %r9, %rcx # not including junk bits + lea -8(%rdi), %rdx + cmovnz %rdx, %r10 # remember location of current mismatch + cmovnz %rcx, %r11 + +0: mov (%rdi), %rax # str + mov %rsi, %rcx + xor %rax, %rcx # str ^ c + bswap %rcx # in reverse order, to find last match + lea (%rax, %r8, 1), %rdx # str - 0x01..01 + not %rax # ~str + and %rdx, %rax # (str - 0x01..01) & ~str + and %r9, %rax # not including junk bits + jnz 2f # end of string? + + lea (%rcx, %r8, 1), %rdx # (str ^ c) - 0x01..01 + not %rcx # ~(str ^ c) + and %rdx, %rcx # ((str ^ c - 0x01..01) & ~(str ^ c) + and %r9, %rcx # not including junk bits + cmovnz %rdi, %r10 # remember location of current mismatch + cmovnz %rcx, %r11 + + mov 8(%rdi), %rax # str + add $16, %rdi + mov %rsi, %rcx + xor %rax, %rcx # str ^ c + bswap %rcx + lea (%rax, %r8, 1), %rdx # str - 0x01..01 + not %rax # ~str + and %rdx, %rax # (str - 0x01..01) & ~str + and %r9, %rax # not including junk bits + jz 3b # end of string? + + /* NUL found */ +1: sub $8, %rdi # undo advance past buffer +2: lea (%rcx, %r8, 1), %rdx # (str ^ c) - 0x01..01 + not %rcx # ~(str ^ c) + and %rdx, %rcx # ((str ^ c - 0x01..01) & ~(str ^ c) + and %r9, %rcx # not including junk bits + lea -1(%rax), %rdx + xor %rdx, %rax # mask of bytes in the string + bswap %rdx # in reverse order + and %rdx, %rcx # c found in the tail? + cmovnz %rdi, %r10 + cmovnz %rcx, %r11 + bswap %r11 # unreverse byte order + bsr %r11, %rcx # last location of c in (R10) + shr $3, %rcx # as byte offset + lea (%r10, %rcx, 1), %rax # pointer to match + test %r11, %r11 # was there actually a match? + cmovz %r11, %rax # if not, return null pointer + ret +ARCHEND(strrchr, scalar) + +ARCHENTRY(strrchr, baseline) + mov %edi, %ecx + and $~0xf, %rdi # align to 16 bytes + movdqa (%rdi), %xmm1 + movd %esi, %xmm0 + and $0xf, %ecx # offset from alignment + pxor %xmm2, %xmm2 + mov $-1, %edx + punpcklbw %xmm0, %xmm0 # c -> cc + shl %cl, %edx # bits corresponding to bytes in the string + punpcklwd %xmm0, %xmm0 # cc -> cccc + xor %r8, %r8 # address of latest match + mov $1, %esi # bit mask of latest match + mov %rdi, %r9 # candidate location for next match + add $16, %rdi # advance to next chunk + + /* check for match in head */ + pcmpeqb %xmm1, %xmm2 # NUL byte present? + pshufd $0, %xmm0, %xmm0 # cccc -> cccccccccccccccc + pcmpeqb %xmm0, %xmm1 # c present? + pmovmskb %xmm2, %eax + pmovmskb %xmm1, %ecx + and %edx, %ecx # c present in the string? + and %edx, %eax # NUL present in the string? + jnz .Lend2 + + /* main loop unrolled twice */ + ALIGN_TEXT +0: movdqa (%rdi), %xmm1 + test %ecx, %ecx # was there a match in the last iter.? + cmovnz %r9, %r8 # remember match if any + cmovnz %ecx, %esi + pxor %xmm2, %xmm2 + pcmpeqb %xmm1, %xmm2 # NUL byte present? + pcmpeqb %xmm0, %xmm1 # c present? + pmovmskb %xmm2, %eax + pmovmskb %xmm1, %ecx + test %eax, %eax # end of string in first half? + jnz .Lend + + movdqa 16(%rdi), %xmm1 + test %ecx, %ecx # was there a match in the last iter.? + cmovnz %rdi, %r8 # remember match if any + cmovnz %ecx, %esi + pxor %xmm2, %xmm2 + pcmpeqb %xmm1, %xmm2 # NUL byte present? + pcmpeqb %xmm0, %xmm1 # c present? + pmovmskb %xmm2, %eax + pmovmskb %xmm1, %ecx + lea 16(%rdi), %r9 + add $32, %rdi + test %eax, %eax # end of string in second half? + jz 0b + + ALIGN_TEXT +.Lend2: sub $16, %rdi +.Lend: lea -1(%rax), %edx + xor %edx, %eax # mask of bytes in the string + and %eax, %ecx # c found in the tail? + cmovnz %rdi, %r8 + cmovnz %ecx, %esi + bsr %esi, %esi # last location of c in (R8) + lea (%r8, %rsi, 1), %rax # pointer to match + ret +ARCHEND(strrchr, baseline) + .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/string/memccpy.c b/lib/libc/amd64/string/strsep.c copy from lib/libc/string/memccpy.c copy to lib/libc/amd64/string/strsep.c --- a/lib/libc/string/memccpy.c +++ b/lib/libc/amd64/string/strsep.c @@ -1,8 +1,8 @@ /*- - * SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2023 The FreeBSD Foundation * - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,37 +12,46 @@ * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * 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 REGENTS OR CONTRIBUTORS BE LIABLE + * 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. + * SUCH DAMAGE */ +#include #include -void * -memccpy(void *t, const void *f, int c, size_t n) +size_t __strcspn(const char *, const char *); + +/* + * We have a fast strcspn() on amd64. Use it over a direct + * implementation of strsep for better performance. + */ +char * +strsep(char **stringp, const char *delim) { + size_t n; + char *s; - if (n) { - unsigned char *tp = t; - const unsigned char *fp = f; - unsigned char uc = c; - do { - if ((*tp++ = *fp++) == uc) - return (tp); - } while (--n != 0); + s = *stringp; + if (s == NULL) + return (NULL); + + n = __strcspn(s, delim); + if (s[n] == '\0') + *stringp = NULL; + else { + s[n] = '\0'; + *stringp = s + n + 1; } - return (0); + + return (s); } diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -1586,17 +1586,32 @@ { wint_t i, s, n; + /* Exclude the complicated cases we don't want to deal with */ + if (cs->nranges != 0 || cs->ntypes != 0 || cs->icase != 0) + return (OUT); + + if (cs->nwides > 1) + return (OUT); + + /* Count the number of characters present in the bitmap */ for (i = n = 0; i < NC; i++) if (CHIN(cs, i)) { n++; s = i; } - if (n == 1) - return (s); - if (cs->nwides == 1 && cs->nranges == 0 && cs->ntypes == 0 && - cs->icase == 0) + + if (n > 1) + return (OUT); + + if (n == 1) { + if (cs->nwides == 0) + return (s); + else + return (OUT); + } + if (cs->nwides == 1) return (cs->wides[0]); - /* Don't bother handling the other cases. */ + return (OUT); } diff --git a/lib/libc/string/bstring.3 b/lib/libc/string/bstring.3 --- a/lib/libc/string/bstring.3 +++ b/lib/libc/string/bstring.3 @@ -27,7 +27,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 4, 1993 +.Dd December 5, 2023 .Dt BSTRING 3 .Os .Sh NAME @@ -56,7 +56,12 @@ .Ft int .Fn memcmp "const void *b1" "const void *b2" "size_t len" .Ft void * -.Fn memccpy "void *dst" "const void *src" "int c" "size_t len" +.Fo memccpy +.Fa "void * restrict dst" +.Fa "const void * restrict src" +.Fa "int c" +.Fa "size_t len" +.Fc .Ft void * .Fn memcpy "void *dst" "const void *src" "size_t len" .Ft void * @@ -78,6 +83,7 @@ .Xr memccpy 3 , .Xr memchr 3 , .Xr memcmp 3 , +.Xr memccpy 3 , .Xr memcpy 3 , .Xr memmove 3 , .Xr memset 3 diff --git a/lib/libc/string/memccpy.3 b/lib/libc/string/memccpy.3 --- a/lib/libc/string/memccpy.3 +++ b/lib/libc/string/memccpy.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 9, 1993 +.Dd December 5, 2023 .Dt MEMCCPY 3 .Os .Sh NAME @@ -36,7 +36,12 @@ .Sh SYNOPSIS .In string.h .Ft void * -.Fn memccpy "void *dst" "const void *src" "int c" "size_t len" +.Fo memccpy +.Fa "void * restrict dst" +.Fa "const void * restrict src" +.Fa "int c" +.Fa "size_t len" +.Fc .Sh DESCRIPTION The .Fn memccpy @@ -59,13 +64,35 @@ Otherwise, .Fa len bytes are copied, and a NULL pointer is returned. +If +.Fa src +and +.Fa dst +overlap, behavior is undefined. .Sh SEE ALSO .Xr bcopy 3 , .Xr memcpy 3 , .Xr memmove 3 , .Xr strcpy 3 +.Sh STANDARDS +The +.Fn memccpy +function conforms to +.St -p1003.1-2004 +and +.\" St -isoC-2024 . +ISO/IEC 9899:2024 (\(lqISO\~C23\(rq). .Sh HISTORY The .Fn memccpy function first appeared in -.Bx 4.4 . +.Bx 4.4 +and was first specified in the +.\" St -svid1 . +System\~V Interface Definition, First Edition (\(lqSVID1\(rq). +The +.Ft restrict +keyword was added to the prototype in +.Fx 5.0.0 +in accordance with the updated specification of +.St -p1003.1-2004 . diff --git a/lib/libc/string/memccpy.c b/lib/libc/string/memccpy.c --- a/lib/libc/string/memccpy.c +++ b/lib/libc/string/memccpy.c @@ -32,7 +32,7 @@ #include void * -memccpy(void *t, const void *f, int c, size_t n) +memccpy(void * restrict t, const void * restrict f, int c, size_t n) { if (n) { diff --git a/lib/libc/tests/regex/multibyte.sh b/lib/libc/tests/regex/multibyte.sh --- a/lib/libc/tests/regex/multibyte.sh +++ b/lib/libc/tests/regex/multibyte.sh @@ -1,4 +1,3 @@ - atf_test_case bmpat bmpat_head() { @@ -45,8 +44,50 @@ echo $c | atf_check -o "inline:$c\n" sed -ne "/$a/Ip" } +atf_test_case mbset cleanup +mbset_head() +{ + atf_set "descr" "Check multibyte sets matching" +} +mbset_body() +{ + export LC_CTYPE="C.UTF-8" + + # This involved an erroneously implemented optimization which reduces + # single-element sets to an exact match with a single codepoint. + # Match sets record small-codepoint characters in a bitmap and + # large-codepoint characters in an array; the optimization would falsely + # trigger if either the bitmap or the array was a singleton, ignoring + # the members of the other side of the set. + # + # To exercise this, we construct sets which have one member of one side + # and one or more of the other, and verify that all members can be + # found. + printf "a" > mbset; atf_check -o not-empty sed -ne '/[aà]/p' mbset + printf "à" > mbset; atf_check -o not-empty sed -ne '/[aà]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -ne '/[aàá]/p' mbset + printf "à" > mbset; atf_check -o not-empty sed -ne '/[aàá]/p' mbset + printf "á" > mbset; atf_check -o not-empty sed -ne '/[aàá]/p' mbset + printf "à" > mbset; atf_check -o not-empty sed -ne '/[abà]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -ne '/[abà]/p' mbset + printf "b" > mbset; atf_check -o not-empty sed -ne '/[abà]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -Ene '/[aà]/p' mbset + printf "à" > mbset; atf_check -o not-empty sed -Ene '/[aà]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -Ene '/[aàá]/p' mbset + printf "à" > mbset; atf_check -o not-empty sed -Ene '/[aàá]/p' mbset + printf "á" > mbset; atf_check -o not-empty sed -Ene '/[aàá]/p' mbset + printf "à" > mbset; atf_check -o not-empty sed -Ene '/[abà]/p' mbset + printf "a" > mbset; atf_check -o not-empty sed -Ene '/[abà]/p' mbset + printf "b" > mbset; atf_check -o not-empty sed -Ene '/[abà]/p' mbset +} +mbset_cleanup() +{ + rm -f mbset +} + atf_init_test_cases() { atf_add_test_case bmpat atf_add_test_case icase + atf_add_test_case mbset } diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile --- a/lib/libc/tests/string/Makefile +++ b/lib/libc/tests/string/Makefile @@ -9,12 +9,16 @@ ATF_TESTS_C+= fls_test ATF_TESTS_C+= flsl_test ATF_TESTS_C+= flsll_test +ATF_TESTS_C+= memccpy_test ATF_TESTS_C+= memcmp_test +ATF_TESTS_C+= memrchr_test ATF_TESTS_C+= memset_s_test +ATF_TESTS_C+= strncmp_test ATF_TESTS_C+= stpncpy_test ATF_TESTS_C+= strcmp2_test ATF_TESTS_C+= strcspn_test ATF_TESTS_C+= strerror2_test +ATF_TESTS_C+= strlcpy_test ATF_TESTS_C+= strspn_test ATF_TESTS_C+= strverscmp_test ATF_TESTS_C+= strxfrm_test diff --git a/lib/libc/tests/string/memccpy_test.c b/lib/libc/tests/string/memccpy_test.c new file mode 100644 --- /dev/null +++ b/lib/libc/tests/string/memccpy_test.c @@ -0,0 +1,205 @@ +/*- + * Copyright (c) 2009 David Schultz + * Copyright (c) 2023 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +void *(*memccpy_fn)(void *restrict, const void *restrict, int, size_t); + +static char * +makebuf(size_t len, int guard_at_end) +{ + char *buf; + size_t alloc_size, page_size; + + page_size = getpagesize(); + alloc_size = roundup2(len, page_size) + page_size; + + buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); + assert(buf); + if (guard_at_end) { + assert(munmap(buf + alloc_size - page_size, page_size) == 0); + return (buf + alloc_size - page_size - len); + } else { + assert(munmap(buf, page_size) == 0); + return (buf + page_size); + } +} + +static void +test_memccpy(const char *s) +{ + char *src, *dst, *expected; + size_t size, bufsize, x; + int i, j; + + size = strlen(s) + 1; + for (i = 0; i <= 1; i++) { + for (j = 0; j <= 1; j++) { + for (bufsize = 0; bufsize <= size + 10; bufsize++) { + src = makebuf(size, i); + memcpy(src, s, size); + dst = makebuf(bufsize, j); + memset(dst, 'X', bufsize); + expected = bufsize >= size ? dst + size : NULL; + assert(memccpy_fn(dst, src, src[size-1], bufsize) == expected); + assert(bufsize == 0 || strncmp(src, dst, bufsize - 1) == 0); + for (x = size; x < bufsize; x++) + assert(dst[x] == 'X'); + } + } + } +} + +static void +test_sentinel(char *dest, char *src, size_t destlen, size_t srclen) +{ + size_t i, effective_len; + void *res, *wantres; + const char *fail = NULL; + char terminator; + + for (i = 0; i < srclen; i++) + /* src will never include (){} */ + src[i] = '0' + i; + + /* source sentinels: not to be copied */ + src[-1] = '('; + src[srclen] = ')'; + + memset(dest, '\xee', destlen); + + /* destination sentinels: not to be touched */ + dest[-1] = '{'; + dest[destlen] = '}'; + + effective_len = srclen < destlen ? srclen : destlen; + wantres = srclen <= destlen ? dest + srclen : NULL; + terminator = src[srclen-1]; + res = memccpy_fn(dest, src, terminator, destlen); + + if (dest[-1] != '{') + fail = "start sentinel overwritten"; + else if (dest[destlen] != '}') + fail = "end sentinel overwritten"; + else if (res != wantres) + fail = "incorrect return value"; + else if (destlen > 0 && memcmp(src, dest, effective_len) != 0) + fail = "string not copied correctly"; + else for (i = srclen; i < destlen; i++) + if (dest[i] != '\xee') { + fail = "buffer mutilated behind string"; + break; + } + + if (fail) + atf_tc_fail_nonfatal("%s\n" + "memccpy(%p \"%s\", %p \"%s\", %u '%c', %zu) = %p (want %p)\n", + fail, dest, dest, src, src, terminator, terminator, destlen, res, wantres); +} + +ATF_TC_WITHOUT_HEAD(null); +ATF_TC_BODY(null, tc) +{ + ATF_CHECK_EQ(memccpy_fn(NULL, "foo", 42, 0), NULL); +} + +ATF_TC(zero_extension); +ATF_TC_HEAD(zero_extension, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Ensure the upper bits of the terminator are ignored"); +} +ATF_TC_BODY(zero_extension, tc) +{ + int mask = -1 & ~UCHAR_MAX; + char buf[16]; + + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ(memccpy(buf, "foobar", 'r', sizeof(buf)), buf + sizeof("foobar") - 1); + ATF_CHECK_EQ(memcmp(buf, "foobar", sizeof("foobar") - 1), 0); + + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ(memccpy(buf, "foobar", mask | 'r', sizeof(buf)), buf + sizeof("foobar") - 1); + ATF_CHECK_EQ(memcmp(buf, "foobar", sizeof("foobar") - 1), 0); +} + +ATF_TC_WITHOUT_HEAD(bounds); +ATF_TC_BODY(bounds, tc) +{ + size_t i; + char buf[64]; + + for (i = 0; i < sizeof(buf) - 1; i++) { + buf[i] = ' ' + i; + test_memccpy(buf); + } +} + +ATF_TC_WITHOUT_HEAD(alignments); +ATF_TC_BODY(alignments, tc) +{ + size_t srcalign, destalign, srclen, destlen; + char src[15+2+64]; /* 15 offsets + 64 max length + sentinels */ + char dest[15+2+64]; /* 15 offsets + 64 max length + sentinels */ + + for (srcalign = 0; srcalign < 16; srcalign++) + for (destalign = 0; destalign < 16; destalign++) + for (srclen = 1; srclen < 64; srclen++) + for (destlen = 0; destlen < 64; destlen++) + test_sentinel(dest+destalign+1, + src+srcalign+1, destlen, srclen); +} + +ATF_TP_ADD_TCS(tp) +{ + void *dl_handle; + + dl_handle = dlopen(NULL, RTLD_LAZY); + memccpy_fn = dlsym(dl_handle, "test_memccpy"); + if (memccpy_fn == NULL) + memccpy_fn = memccpy; + + ATF_TP_ADD_TC(tp, null); + ATF_TP_ADD_TC(tp, zero_extension); + ATF_TP_ADD_TC(tp, bounds); + ATF_TP_ADD_TC(tp, alignments); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/string/memrchr_test.c b/lib/libc/tests/string/memrchr_test.c new file mode 100644 --- /dev/null +++ b/lib/libc/tests/string/memrchr_test.c @@ -0,0 +1,116 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Robert Clausecker + */ + +#include + +#include +#include +#include + +#include + +static void *(*memrchr_fn)(const void *, int, size_t); + +ATF_TC_WITHOUT_HEAD(null); +ATF_TC_BODY(null, tc) +{ + ATF_CHECK_EQ(memrchr_fn(NULL, 42, 0), NULL); +} + +ATF_TC_WITHOUT_HEAD(not_found); +ATF_TC_BODY(not_found, tc) +{ + size_t i, j; + char buf[1+15+64+1]; /* 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] = 'X'; + ATF_CHECK_EQ(memrchr_fn(buf + i + 1, 'X', j), NULL); + buf[i + j + 1] = '-'; + } +} + +static void +do_found_test(char buf[], size_t len, size_t first, size_t second) +{ + /* invariant: first <= second */ + + buf[first] = 'X'; + buf[second] = 'X'; + ATF_CHECK_EQ(memrchr_fn(buf, 'X', len), buf + second); + buf[first] = '-'; + buf[second] = '-'; +} + +ATF_TC_WITHOUT_HEAD(found); +ATF_TC_BODY(found, tc) +{ + size_t i, j, k, l; + char buf[1+15+64+1]; + + 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] = 'X'; + do_found_test(buf + i + 1, j, l, k); + buf[i + j + 1] = '-'; + } +} + +/* check that the right character is found */ +static void +do_values_test(unsigned char buf[], size_t len, size_t i, int c) +{ + /* sentinels */ + buf[-1] = c; + buf[len] = c; + memset(buf, c + 1, len); + + if (i < len) { + buf[i] = c; + ATF_CHECK_EQ(memrchr_fn(buf, c, len), buf + i); + } else + ATF_CHECK_EQ(memrchr_fn(buf, c, len), NULL); +} + +ATF_TC_WITHOUT_HEAD(values); +ATF_TC_BODY(values, tc) +{ + size_t i, j, k; + int c; + unsigned char buf[1+15+64+1]; + + 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); + memrchr_fn = dlsym(dl_handle, "test_memrchr"); + if (memrchr_fn == NULL) + memrchr_fn = memrchr; + + ATF_TP_ADD_TC(tp, null); + 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/libc/tests/string/stpncpy_test.c b/lib/libc/tests/string/stpncpy_test.c --- a/lib/libc/tests/string/stpncpy_test.c +++ b/lib/libc/tests/string/stpncpy_test.c @@ -1,7 +1,11 @@ /*- * Copyright (c) 2009 David Schultz + * Copyright (c) 2023 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -27,12 +31,15 @@ #include #include #include +#include #include #include #include #include +static char *(*stpncpy_fn)(char *restrict, const char *restrict, size_t); + static char * makebuf(size_t len, int guard_at_end) { @@ -69,7 +76,7 @@ dst = makebuf(bufsize, j); memset(dst, 'X', bufsize); len = (bufsize < size) ? bufsize : size - 1; - assert(stpncpy(dst, src, bufsize) == dst+len); + assert(stpncpy_fn(dst, src, bufsize) == dst+len); assert(memcmp(src, dst, len) == 0); for (x = len; x < bufsize; x++) assert(dst[x] == '\0'); @@ -78,33 +85,97 @@ } } -ATF_TC_WITHOUT_HEAD(nul); -ATF_TC_BODY(nul, tc) +static void +test_sentinel(char *dest, char *src, size_t destlen, size_t srclen) { + size_t i; + const char *res, *wantres; + const char *fail = NULL; + + for (i = 0; i < srclen; i++) + /* src will never include (){} */ + src[i] = '0' + i; + src[srclen] = '\0'; + + /* source sentinels: not to be copied */ + src[-1] = '('; + src[srclen+1] = ')'; + + memset(dest, 0xee, destlen); + + /* destination sentinels: not to be touched */ + dest[-1] = '{'; + dest[destlen] = '}'; + + wantres = dest + (srclen > destlen ? destlen : srclen); + res = stpncpy_fn(dest, src, destlen); + + if (dest[-1] != '{') + fail = "start sentinel overwritten"; + else if (dest[destlen] != '}') + fail = "end sentinel overwritten"; + else if (strncmp(src, dest, destlen) != 0) + fail = "string not copied correctly"; + else if (res != wantres) + fail = "incorrect return value"; + else for (i = srclen; i < destlen; i++) + if (dest[i] != '\0') { + fail = "incomplete NUL padding"; + break; + } - test_stpncpy(""); + if (fail) + atf_tc_fail_nonfatal("%s\n" + "stpncpy(%p \"%s\", %p \"%s\", %zu) = %p (want %p)\n", + fail, dest, dest, src, src, destlen, res, wantres); } -ATF_TC_WITHOUT_HEAD(foo); -ATF_TC_BODY(foo, tc) +ATF_TC_WITHOUT_HEAD(null); +ATF_TC_BODY(null, tc) { - - test_stpncpy("foo"); + ATF_CHECK_EQ(stpncpy_fn(NULL, NULL, 0), NULL); } -ATF_TC_WITHOUT_HEAD(glorp); -ATF_TC_BODY(glorp, tc) +ATF_TC_WITHOUT_HEAD(bounds); +ATF_TC_BODY(bounds, tc) { + size_t i; + char buf[64+1]; - test_stpncpy("glorp"); + for (i = 0; i < sizeof(buf) - 1; i++) { + buf[i] = ' ' + i; + buf[i+1] = '\0'; + test_stpncpy(buf); + } +} + +ATF_TC_WITHOUT_HEAD(alignments); +ATF_TC_BODY(alignments, tc) +{ + size_t srcalign, destalign, srclen, destlen; + char src[15+3+64]; /* 15 offsets + 64 max length + NUL + sentinels */ + char dest[15+2+64]; /* 15 offsets + 64 max length + sentinels */ + + for (srcalign = 0; srcalign < 16; srcalign++) + for (destalign = 0; destalign < 16; destalign++) + for (srclen = 0; srclen < 64; srclen++) + for (destlen = 0; destlen < 64; destlen++) + test_sentinel(dest+destalign+1, + src+srcalign+1, destlen, srclen); } ATF_TP_ADD_TCS(tp) { + void *dl_handle; + + dl_handle = dlopen(NULL, RTLD_LAZY); + stpncpy_fn = dlsym(dl_handle, "test_stpncpy"); + if (stpncpy_fn == NULL) + stpncpy_fn = stpncpy; - ATF_TP_ADD_TC(tp, nul); - ATF_TP_ADD_TC(tp, foo); - ATF_TP_ADD_TC(tp, glorp); + ATF_TP_ADD_TC(tp, null); + ATF_TP_ADD_TC(tp, bounds); + ATF_TP_ADD_TC(tp, alignments); return (atf_no_error()); } diff --git a/lib/libc/tests/string/strcspn_test.c b/lib/libc/tests/string/strcspn_test.c --- a/lib/libc/tests/string/strcspn_test.c +++ b/lib/libc/tests/string/strcspn_test.c @@ -150,7 +150,7 @@ #ifndef STRSPN /* test all positions in which set could match buf */ static void -test_match_positions(char *buf, char *set, size_t buflen, size_t setlen) +test_match_positions(char *buf, char *set, size_t buflen, size_t setlen) { size_t i, j, outcome; @@ -206,6 +206,54 @@ test_match_positions(buf, set, 16, 8); test_match_positions(buf, set, 8, 8); } + +/* if there are two matches, check that the earlier match is taken */ +static void +test_match_order(char *buf, char *set, size_t buflen, size_t setlen) +{ + size_t i, j, k, l, outcome; + + memset(buf, '-', buflen); + + for (i = 0; i < setlen; i++) + set[i] = 'A' + i; + + buf[buflen] = '\0'; + set[setlen] = '\0'; + + for (i = 0; i < setlen; i++) + for (j = 0; j < setlen; j++) + for (k = 0; k + 1 < buflen; k++) + for (l = k + 1; l < buflen; l++) { + buf[k] = set[i]; + buf[l] = set[j]; + outcome = strcspn(buf, set); + ATF_CHECK_EQ_MSG(k, outcome, + "strcspn(\"%s\", \"%s\") = %zu != %zu", + buf, set, outcome, k); + buf[k] = '-'; + buf[l] = '-'; + } +} + +ATF_TC_WITHOUT_HEAD(match_order); +ATF_TC_BODY(match_order, tc) +{ + char buf[33], set[65]; + + test_match_order(buf, set, 32, 64); + test_match_order(buf, set, 16, 64); + test_match_order(buf, set, 8, 64); + test_match_order(buf, set, 32, 32); + test_match_order(buf, set, 16, 32); + test_match_order(buf, set, 8, 32); + test_match_order(buf, set, 32, 16); + test_match_order(buf, set, 16, 16); + test_match_order(buf, set, 8, 16); + test_match_order(buf, set, 32, 8); + test_match_order(buf, set, 16, 8); + test_match_order(buf, set, 8, 8); +} #endif /* !defined(STRSPN) */ ATF_TP_ADD_TCS(tp) @@ -214,6 +262,7 @@ ATF_TP_ADD_TC(tp, set_alignments); #ifndef STRSPN ATF_TP_ADD_TC(tp, match_positions); + ATF_TP_ADD_TC(tp, match_order); #endif return (atf_no_error()); diff --git a/lib/libc/tests/string/strlcpy_test.c b/lib/libc/tests/string/strlcpy_test.c new file mode 100644 --- /dev/null +++ b/lib/libc/tests/string/strlcpy_test.c @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2009 David Schultz + * Copyright (c) 2023 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +size_t (*strlcpy_fn)(char *restrict, const char *restrict, size_t); + +static char * +makebuf(size_t len, int guard_at_end) +{ + char *buf; + size_t alloc_size, page_size; + + page_size = getpagesize(); + alloc_size = roundup2(len, page_size) + page_size; + + buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); + assert(buf); + if (guard_at_end) { + assert(munmap(buf + alloc_size - page_size, page_size) == 0); + return (buf + alloc_size - page_size - len); + } else { + assert(munmap(buf, page_size) == 0); + return (buf + page_size); + } +} + +static void +test_strlcpy(const char *s) +{ + char *src, *dst; + size_t size, bufsize, x; + int i, j; + + size = strlen(s) + 1; + for (i = 0; i <= 1; i++) { + for (j = 0; j <= 1; j++) { + for (bufsize = 0; bufsize <= size + 10; bufsize++) { + src = makebuf(size, i); + memcpy(src, s, size); + dst = makebuf(bufsize, j); + memset(dst, 'X', bufsize); + assert(strlcpy_fn(dst, src, bufsize) == size-1); + assert(bufsize == 0 || strncmp(src, dst, bufsize - 1) == 0); + for (x = size; x < bufsize; x++) + assert(dst[x] == 'X'); + } + } + } +} + +static void +test_sentinel(char *dest, char *src, size_t destlen, size_t srclen) +{ + size_t i; + size_t res, wantres; + const char *fail = NULL; + + for (i = 0; i < srclen; i++) + /* src will never include (){} */ + src[i] = '0' + i; + src[srclen] = '\0'; + + /* source sentinels: not to be copied */ + src[-1] = '('; + src[srclen+1] = ')'; + + memset(dest, '\xee', destlen); + + /* destination sentinels: not to be touched */ + dest[-1] = '{'; + dest[destlen] = '}'; + + wantres = srclen; + res = strlcpy_fn(dest, src, destlen); + + if (dest[-1] != '{') + fail = "start sentinel overwritten"; + else if (dest[destlen] != '}') + fail = "end sentinel overwritten"; + else if (res != wantres) + fail = "incorrect return value"; + else if (destlen > 0 && strncmp(src, dest, destlen - 1) != 0) + fail = "string not copied correctly"; + else if (destlen > 0 && srclen >= destlen - 1 && dest[destlen-1] != '\0') + fail = "string not NUL terminated"; + else for (i = srclen + 1; i < destlen; i++) + if (dest[i] != '\xee') { + fail = "buffer mutilated behind string"; + break; + } + + if (fail) + atf_tc_fail_nonfatal("%s\n" + "strlcpy(%p \"%s\", %p \"%s\", %zu) = %zu (want %zu)\n", + fail, dest, dest, src, src, destlen, res, wantres); +} + +ATF_TC_WITHOUT_HEAD(null); +ATF_TC_BODY(null, tc) +{ + ATF_CHECK_EQ(strlcpy_fn(NULL, "foo", 0), 3); +} + +ATF_TC_WITHOUT_HEAD(bounds); +ATF_TC_BODY(bounds, tc) +{ + size_t i; + char buf[64+1]; + + for (i = 0; i < sizeof(buf) - 1; i++) { + buf[i] = ' ' + i; + buf[i+1] = '\0'; + test_strlcpy(buf); + } +} + +ATF_TC_WITHOUT_HEAD(alignments); +ATF_TC_BODY(alignments, tc) +{ + size_t srcalign, destalign, srclen, destlen; + char src[15+3+64]; /* 15 offsets + 64 max length + NUL + sentinels */ + char dest[15+2+64]; /* 15 offsets + 64 max length + sentinels */ + + for (srcalign = 0; srcalign < 16; srcalign++) + for (destalign = 0; destalign < 16; destalign++) + for (srclen = 0; srclen < 64; srclen++) + for (destlen = 0; destlen < 64; destlen++) + test_sentinel(dest+destalign+1, + src+srcalign+1, destlen, srclen); +} + +ATF_TP_ADD_TCS(tp) +{ + void *dl_handle; + + dl_handle = dlopen(NULL, RTLD_LAZY); + strlcpy_fn = dlsym(dl_handle, "test_strlcpy"); + if (strlcpy_fn == NULL) + strlcpy_fn = strlcpy; + + ATF_TP_ADD_TC(tp, null); + ATF_TP_ADD_TC(tp, bounds); + ATF_TP_ADD_TC(tp, alignments); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/string/strncmp_test.c b/lib/libc/tests/string/strncmp_test.c new file mode 100644 --- /dev/null +++ b/lib/libc/tests/string/strncmp_test.c @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Robert Clausecker + * under sponsorship from the FreeBSD Foundation. + * + * 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 + +#include +#include +#include + +int (*volatile strncmp_fn)(const char *, const char *, size_t); + +static void +alignment_testcase(char *a, char *b, int want, size_t len) +{ + int res; + + res = strncmp_fn(a, b, len); + ATF_CHECK_MSG(want == (res > 0) - (res < 0), + "strcmp(%p \"%s\", %p \"%s\", %zu) = %d != %d", + (void *)a, a, (void *)b, b, len, res, want); +} + +static void +check_strncmp_alignments(char a[], char b[], + size_t a_off, size_t b_off, size_t len, size_t pos) +{ + char *a_str, *b_str, a_orig, b_orig; + + a[a_off] = '\0'; + b[b_off] = '\0'; + + a_str = a + a_off + 1; + b_str = b + b_off + 1; + + a_str[len] = '\0'; + b_str[len] = '\0'; + a_str[len+1] = 'A'; + b_str[len+1] = 'B'; + + a_orig = a_str[pos]; + b_orig = b_str[pos]; + + alignment_testcase(a_str, b_str, 0, len + 16); + alignment_testcase(a_str, b_str, 0, len + 1); + alignment_testcase(a_str, b_str, 0, len); + + if (pos < len) { + a_str[pos] = '\0'; + alignment_testcase(a_str, b_str, -1, len + 16); + alignment_testcase(a_str, b_str, -1, len + 1); + alignment_testcase(a_str, b_str, -1, len); + alignment_testcase(a_str, b_str, -1, pos + 1); + alignment_testcase(a_str, b_str, 0, pos); + a_str[pos] = a_orig; + + b_str[pos] = '\0'; + alignment_testcase(a_str, b_str, 1, len + 16); + alignment_testcase(a_str, b_str, 1, len + 1); + alignment_testcase(a_str, b_str, 1, len); + alignment_testcase(a_str, b_str, 1, pos + 1); + alignment_testcase(a_str, b_str, 0, pos); + b_str[pos] = b_orig; + } + + a_str[pos] = 'X'; + alignment_testcase(a_str, b_str, 1, len + 16); + alignment_testcase(a_str, b_str, 0, pos); + alignment_testcase(a_str, b_str, 1, pos + 1); + if (pos < len) { + alignment_testcase(a_str, b_str, 1, len); + alignment_testcase(a_str, b_str, 1, len + 1); + } + a_str[pos] = a_orig; + + b_str[pos] = 'X'; + alignment_testcase(a_str, b_str, -1, len + 16); + alignment_testcase(a_str, b_str, 0, pos); + alignment_testcase(a_str, b_str, -1, pos + 1); + if (pos < len) { + alignment_testcase(a_str, b_str, -1, len); + alignment_testcase(a_str, b_str, -1, len + 1); + } + b_str[pos] = b_orig; + + a[a_off] = '-'; + b[b_off] = '-'; + a_str[len] = '-'; + b_str[len] = '-'; + a_str[len+1] = '-'; + b_str[len+1] = '-'; +} + +ATF_TC(strncmp_alignments); +ATF_TC_HEAD(strncmp_alignments, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test strncmp(3) with various alignments"); +} + +ATF_TC_BODY(strncmp_alignments, tc) +{ + size_t a_off, b_off, len, pos; + char a[64+16+16+3], b[64+16+16+3]; + + memset(a, '-', sizeof(a)); + memset(b, '-', sizeof(b)); + a[sizeof(a) - 1] = '\0'; + b[sizeof(b) - 1] = '\0'; + + for (a_off = 0; a_off < 16; a_off++) + for (b_off = 0; b_off < 16; b_off++) + for (len = 1; len <= 64; len++) + for (pos = 0; pos <= len; pos++) + check_strncmp_alignments(a, b, a_off, b_off, len, pos); +} + +ATF_TC(strncmp_null); +ATF_TC_HEAD(strncmp_null, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test strncmp(3) with null pointers"); +} + +ATF_TC_BODY(strncmp_null, tc) +{ + alignment_testcase(NULL, NULL, 0, 0); +} + +ATF_TP_ADD_TCS(tp) +{ + void *dl_handle; + + dl_handle = dlopen(NULL, RTLD_LAZY); + strncmp_fn = dlsym(dl_handle, "test_strncmp"); + if (strncmp_fn == NULL) + strncmp_fn = strncmp; + + ATF_TP_ADD_TC(tp, strncmp_alignments); + ATF_TP_ADD_TC(tp, strncmp_null); + + return atf_no_error(); +} diff --git a/lib/libclang_rt/asan/Makefile b/lib/libclang_rt/asan/Makefile --- a/lib/libclang_rt/asan/Makefile +++ b/lib/libclang_rt/asan/Makefile @@ -19,7 +19,6 @@ SRCS+= asan/asan_poisoning.cpp SRCS+= asan/asan_posix.cpp SRCS+= asan/asan_preinit.cpp -SRCS+= asan/asan_premap_shadow.cpp SRCS+= asan/asan_report.cpp SRCS+= asan/asan_rtl.cpp SRCS+= asan/asan_shadow_setup.cpp @@ -28,7 +27,6 @@ SRCS+= asan/asan_suppressions.cpp SRCS+= asan/asan_thread.cpp SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sancov_flags.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp @@ -66,6 +64,7 @@ SRCS+= sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp SRCS+= sanitizer_common/sanitizer_symbolizer_report.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/asan_dynamic/Makefile b/lib/libclang_rt/asan_dynamic/Makefile --- a/lib/libclang_rt/asan_dynamic/Makefile +++ b/lib/libclang_rt/asan_dynamic/Makefile @@ -22,7 +22,6 @@ SRCS+= asan/asan_poisoning.cpp SRCS+= asan/asan_posix.cpp SRCS+= asan/asan_preinit.cpp -SRCS+= asan/asan_premap_shadow.cpp SRCS+= asan/asan_report.cpp SRCS+= asan/asan_rtl.cpp SRCS+= asan/asan_shadow_setup.cpp @@ -31,7 +30,6 @@ SRCS+= asan/asan_suppressions.cpp SRCS+= asan/asan_thread.cpp SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sancov_flags.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp @@ -69,6 +67,7 @@ SRCS+= sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp SRCS+= sanitizer_common/sanitizer_symbolizer_report.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/cfi/Makefile b/lib/libclang_rt/cfi/Makefile --- a/lib/libclang_rt/cfi/Makefile +++ b/lib/libclang_rt/cfi/Makefile @@ -5,7 +5,6 @@ SRCS+= cfi/cfi.cpp SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp SRCS+= sanitizer_common/sanitizer_common.cpp @@ -29,6 +28,7 @@ SRCS+= sanitizer_common/sanitizer_procmaps_common.cpp SRCS+= sanitizer_common/sanitizer_suppressions.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/cfi_diag/Makefile b/lib/libclang_rt/cfi_diag/Makefile --- a/lib/libclang_rt/cfi_diag/Makefile +++ b/lib/libclang_rt/cfi_diag/Makefile @@ -5,7 +5,6 @@ SRCS+= cfi/cfi.cpp SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sancov_flags.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp @@ -43,6 +42,7 @@ SRCS+= sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp SRCS+= sanitizer_common/sanitizer_symbolizer_report.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/dd/Makefile b/lib/libclang_rt/dd/Makefile --- a/lib/libclang_rt/dd/Makefile +++ b/lib/libclang_rt/dd/Makefile @@ -4,7 +4,6 @@ LIB= clang_rt.dd-${CRTARCH} SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp SRCS+= sanitizer_common/sanitizer_common.cpp @@ -28,6 +27,7 @@ SRCS+= sanitizer_common/sanitizer_procmaps_common.cpp SRCS+= sanitizer_common/sanitizer_suppressions.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/msan/Makefile b/lib/libclang_rt/msan/Makefile --- a/lib/libclang_rt/msan/Makefile +++ b/lib/libclang_rt/msan/Makefile @@ -4,10 +4,10 @@ LIB= clang_rt.msan-${CRTARCH} SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= msan/msan.cpp SRCS+= msan/msan_allocator.cpp SRCS+= msan/msan_chained_origin_depot.cpp +SRCS+= msan/msan_dl.cpp SRCS+= msan/msan_interceptors.cpp SRCS+= msan/msan_linux.cpp SRCS+= msan/msan_poisoning.cpp @@ -50,6 +50,7 @@ SRCS+= sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp SRCS+= sanitizer_common/sanitizer_symbolizer_report.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/safestack/Makefile b/lib/libclang_rt/safestack/Makefile --- a/lib/libclang_rt/safestack/Makefile +++ b/lib/libclang_rt/safestack/Makefile @@ -4,7 +4,6 @@ LIB= clang_rt.safestack-${CRTARCH} SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= safestack/safestack.cpp .include diff --git a/lib/libclang_rt/stats/Makefile b/lib/libclang_rt/stats/Makefile --- a/lib/libclang_rt/stats/Makefile +++ b/lib/libclang_rt/stats/Makefile @@ -38,6 +38,7 @@ SRCS+= sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp SRCS+= sanitizer_common/sanitizer_symbolizer_report.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/tsan/Makefile b/lib/libclang_rt/tsan/Makefile --- a/lib/libclang_rt/tsan/Makefile +++ b/lib/libclang_rt/tsan/Makefile @@ -4,7 +4,6 @@ LIB= clang_rt.tsan-${CRTARCH} SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sancov_flags.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp @@ -30,7 +29,6 @@ SRCS+= sanitizer_common/sanitizer_printf.cpp SRCS+= sanitizer_common/sanitizer_procmaps_bsd.cpp SRCS+= sanitizer_common/sanitizer_procmaps_common.cpp -SRCS+= sanitizer_common/sanitizer_range.cpp SRCS+= sanitizer_common/sanitizer_stack_store.cpp SRCS+= sanitizer_common/sanitizer_stackdepot.cpp SRCS+= sanitizer_common/sanitizer_stacktrace.cpp @@ -62,7 +60,6 @@ SRCS+= tsan/rtl/tsan_md5.cpp SRCS+= tsan/rtl/tsan_mman.cpp SRCS+= tsan/rtl/tsan_mutexset.cpp -SRCS+= tsan/rtl/tsan_new_delete.cpp SRCS+= tsan/rtl/tsan_platform_linux.cpp SRCS+= tsan/rtl/tsan_platform_posix.cpp SRCS+= tsan/rtl/tsan_preinit.cpp diff --git a/lib/libclang_rt/ubsan_standalone/Makefile b/lib/libclang_rt/ubsan_standalone/Makefile --- a/lib/libclang_rt/ubsan_standalone/Makefile +++ b/lib/libclang_rt/ubsan_standalone/Makefile @@ -4,7 +4,6 @@ LIB= clang_rt.ubsan_standalone-${CRTARCH} SRCS+= interception/interception_linux.cpp -SRCS+= interception/interception_type_test.cpp SRCS+= sanitizer_common/sancov_flags.cpp SRCS+= sanitizer_common/sanitizer_allocator.cpp SRCS+= sanitizer_common/sanitizer_allocator_checks.cpp @@ -42,6 +41,7 @@ SRCS+= sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp SRCS+= sanitizer_common/sanitizer_symbolizer_report.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libclang_rt/xray/Makefile b/lib/libclang_rt/xray/Makefile --- a/lib/libclang_rt/xray/Makefile +++ b/lib/libclang_rt/xray/Makefile @@ -28,6 +28,7 @@ SRCS+= sanitizer_common/sanitizer_procmaps_common.cpp SRCS+= sanitizer_common/sanitizer_suppressions.cpp SRCS+= sanitizer_common/sanitizer_termination.cpp +SRCS+= sanitizer_common/sanitizer_thread_arg_retval.cpp SRCS+= sanitizer_common/sanitizer_thread_registry.cpp SRCS+= sanitizer_common/sanitizer_tls_get_addr.cpp SRCS+= sanitizer_common/sanitizer_type_traits.cpp diff --git a/lib/libifconfig/libifconfig_bridge.c b/lib/libifconfig/libifconfig_bridge.c --- a/lib/libifconfig/libifconfig_bridge.c +++ b/lib/libifconfig/libifconfig_bridge.c @@ -111,7 +111,7 @@ free(bridge); return (-1); } - if (members.ifbic_len <= len) + if ((members.ifbic_len + sizeof(*members.ifbic_req)) < len) break; } if (buf == NULL) { diff --git a/lib/libnetmap/nmreq.c b/lib/libnetmap/nmreq.c --- a/lib/libnetmap/nmreq.c +++ b/lib/libnetmap/nmreq.c @@ -156,11 +156,6 @@ for (pipesep = vpname; pipesep != scan && !index("{}", *pipesep); pipesep++) ; - if (!nm_is_identifier(vpname, pipesep)) { - nmctx_ferror(ctx, "%s: invalid port name '%.*s'", *pifname, - pipesep - vpname, vpname); - goto fail; - } if (pipesep != scan) { pipesep++; if (*pipesep == '\0') { diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -1386,6 +1386,13 @@ { .type = PF_ST_LOG, .off = _OUT(log), .cb = snl_attr_get_uint8 }, { .type = PF_ST_STATE_FLAGS, .off = _OUT(state_flags), .cb = snl_attr_get_uint16 }, { .type = PF_ST_SYNC_FLAGS, .off = _OUT(sync_flags), .cb = snl_attr_get_uint8 }, + { .type = PF_ST_RTABLEID, .off = _OUT(rtableid), .cb = snl_attr_get_int32 }, + { .type = PF_ST_MIN_TTL, .off = _OUT(min_ttl), .cb = snl_attr_get_uint8 }, + { .type = PF_ST_MAX_MSS, .off = _OUT(max_mss), .cb = snl_attr_get_uint16 }, + { .type = PF_ST_DNPIPE, .off = _OUT(dnpipe), .cb = snl_attr_get_uint16 }, + { .type = PF_ST_DNRPIPE, .off = _OUT(dnrpipe), .cb = snl_attr_get_uint16 }, + { .type = PF_ST_RT, .off = _OUT(rt), .cb = snl_attr_get_uint8 }, + { .type = PF_ST_RT_IFNAME, .off = _OUT(rt_ifname), .cb = snl_attr_store_ifname }, }; static struct snl_field_parser fp_state[] = { }; diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8 --- a/sbin/camcontrol/camcontrol.8 +++ b/sbin/camcontrol/camcontrol.8 @@ -745,7 +745,7 @@ Display/edit block descriptors instead of mode page. .It Fl L Use long LBA block descriptors. -Allows number of LBAs bigger then 2^^32. +Allows number of LBAs bigger than 2^^32. .It Fl b Displays mode page data in binary format. .It Fl e @@ -762,7 +762,7 @@ detects that standard input is terminal. .It Fl l Lists all available mode pages. -If specified more then once, also lists subpages. +If specified more than once, also lists subpages. .It Fl m Ar page[,subpage] This specifies the number of the mode page and optionally subpage the user would like to view and/or edit. diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile --- a/sbin/devd/Makefile +++ b/sbin/devd/Makefile @@ -11,10 +11,12 @@ DEVD+= asus.conf .endif +.if ${MK_AUTOFS} != "no" CONFGROUPS+= AUTOFS AUTOFSDIR= ${DEVDDIR} AUTOFS+= autofs.conf AUTOFSPACKAGE= autofs +.endif CONFGROUPS+= DHCLIENT DHCLIENTDIR= ${DEVDDIR} diff --git a/sbin/gvinum/gvinum.8 b/sbin/gvinum/gvinum.8 --- a/sbin/gvinum/gvinum.8 +++ b/sbin/gvinum/gvinum.8 @@ -351,7 +351,7 @@ .Pp .Dl "gvinum start myraid5vol.p0" .Pp -The plex will go up form degraded mode after the rebuild is finished. +The plex will go up from degraded mode after the rebuild is finished. The plex can still be used while the rebuild is in progress, although requests might be delayed. .Pp diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c --- a/sbin/ifconfig/ifieee80211.c +++ b/sbin/ifconfig/ifieee80211.c @@ -70,6 +70,7 @@ #include #include +#define WANT_NET80211 1 #include #include #include @@ -2780,10 +2781,18 @@ { printf("%s", tag); if (ctx->args->verbose) { - const struct ieee80211_ie_vhtcap *vhtcap = - (const struct ieee80211_ie_vhtcap *) ie; - uint32_t vhtcap_info = LE_READ_4(&vhtcap->vht_cap_info); + const struct ieee80211_vht_cap *vhtcap; + uint32_t vhtcap_info; + /* Check that the the right size. */ + if (ie[1] != sizeof(*vhtcap)) { + printf(""); + return; + } + /* Skip Element ID and Length. */ + vhtcap = (const struct ieee80211_vht_cap *)(ie + 2); + + vhtcap_info = LE_READ_4(&vhtcap->vht_cap_info); printf("supp_mcs.rx_mcs_map)); @@ -2803,13 +2812,20 @@ { printf("%s", tag); if (ctx->args->verbose) { - const struct ieee80211_ie_vht_operation *vhtinfo = - (const struct ieee80211_ie_vht_operation *) ie; + const struct ieee80211_vht_operation *vhtinfo; + + /* Check that the the right size. */ + if (ie[1] != sizeof(*vhtinfo)) { + printf(""); + return; + } + /* Skip Element ID and Length. */ + vhtinfo = (const struct ieee80211_vht_operation *)(ie + 2); - printf("", + printf("", vhtinfo->chan_width, - vhtinfo->center_freq_seg1_idx, - vhtinfo->center_freq_seg2_idx, + vhtinfo->center_freq_seq0_idx, + vhtinfo->center_freq_seq1_idx, LE_READ_2(&vhtinfo->basic_mcs_set)); } } diff --git a/sbin/kldload/kldload.8 b/sbin/kldload/kldload.8 --- a/sbin/kldload/kldload.8 +++ b/sbin/kldload/kldload.8 @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 11, 2021 +.Dd December 20, 2023 .Dt KLDLOAD 8 .Os .Sh NAME @@ -114,6 +114,7 @@ required for mounting the root filesystem, should be handled by .Xr loader.conf 5 . .Sh SEE ALSO +.Xr kenv 1 , .Xr kldload 2 , .Xr loader.conf 5 , .Xr rc.conf 5 , diff --git a/share/examples/tests/tests/atf/Makefile b/share/examples/tests/tests/atf/Makefile --- a/share/examples/tests/tests/atf/Makefile +++ b/share/examples/tests/tests/atf/Makefile @@ -46,3 +46,7 @@ @echo "File 1" > ${.TARGET} .include + +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +CWARNFLAGS.printf_test.c+= -Wno-format-truncation +.endif diff --git a/share/examples/tests/tests/plain/Makefile b/share/examples/tests/tests/plain/Makefile --- a/share/examples/tests/tests/plain/Makefile +++ b/share/examples/tests/tests/plain/Makefile @@ -46,3 +46,7 @@ @echo "File 1" > ${.TARGET} .include + +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +CWARNFLAGS.printf_test.c+= -Wno-format-truncation +.endif diff --git a/share/examples/tests/tests/tap/Makefile b/share/examples/tests/tests/tap/Makefile --- a/share/examples/tests/tests/tap/Makefile +++ b/share/examples/tests/tests/tap/Makefile @@ -46,3 +46,7 @@ @echo "File 1" > ${.TARGET} .include + +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +CWARNFLAGS.printf_test.c+= -Wno-format-truncation +.endif diff --git a/share/man/man7/simd.7 b/share/man/man7/simd.7 --- a/share/man/man7/simd.7 +++ b/share/man/man7/simd.7 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE . -.Dd September 2, 2023 +.Dd December 6, 2023 .Dt SIMD 7 .Os .Sh NAME @@ -48,7 +48,7 @@ .Ev ARCHLEVEL can be used to override this mechanism. .Pp -Enhanced functions are present in the following architectures: +Enhanced functions are present for the following architectures: .Bl -column FUNCTION_________ aarch64_ arm_ amd64_ i386_ ppc64_ -offset indent .It Em FUNCTION Ta Em AARCH64 Ta Em ARM Ta Em AMD64 Ta Em I386 Ta Em PPC64 .It bcmp Ta Ta Ta S1 Ta S @@ -58,24 +58,32 @@ .It index Ta S Ta Ta S1 .It ldiv Ta Ta Ta S Ta S .It lldiv Ta Ta Ta S -.It memchr Ta Ta Ta S1 -.It memcmp Ta Ta S Ta S1 Ta S +.It memchr Ta S Ta Ta S1 +.It memcmp Ta S Ta S Ta S1 Ta S +.It memccpy Ta Ta Ta S1 .It memcpy Ta S Ta S Ta S Ta S Ta SV .It memmove Ta S Ta S Ta S Ta S Ta SV -.It memset Ta Ta S Ta S Ta S -.It rindex Ta S -.It stpcpy Ta Ta Ta S1 -.It strcat Ta Ta Ta S Ta S +.It memrchr Ta Ta Ta S1 +.It memset Ta S Ta S Ta S Ta S +.It rindex Ta S Ta Ta S1 Ta S +.It stpcpy Ta S Ta Ta S1 +.It stpncpy Ta Ta Ta S1 +.It strcat Ta Ta Ta S1 Ta S .It strchr Ta S Ta Ta S1 Ta S -.It strchrnul Ta Ta Ta S1 -.It strcmp Ta Ta S Ta S Ta S -.It strcpy Ta Ta Ta S1 Ta S Ta S2 +.It strchrnul Ta S Ta Ta S1 +.It strcmp Ta S Ta S Ta S1 Ta S +.It strcpy Ta S Ta Ta S1 Ta S Ta S2 .It strcspn Ta Ta Ta S2 -.It strlen Ta Ta S Ta S1 -.It strncmp Ta Ta S Ta Ta S -.It strncpy Ta Ta Ta Ta Ta S2 -.It strnlen Ta Ta Ta S1 -.It strrchr Ta S Ta Ta Ta S +.It strlcat Ta Ta Ta S1 +.It strlcpy Ta Ta Ta S1 +.It strlen Ta S Ta S Ta S1 +.It strncat Ta Ta Ta S1 +.It strncmp Ta S Ta S Ta S1 Ta S +.It strncpy Ta Ta Ta S1 Ta Ta S2 +.It strnlen Ta S Ta Ta S1 +.It strrchr Ta S Ta Ta S1 Ta S +.It strpbrk Ta Ta Ta S2 +.It strsep Ta Ta Ta S2 .It strspn Ta Ta Ta S2 .It swab Ta Ta Ta Ta S .It timingsafe_bcmp Ta Ta Ta S1 @@ -207,14 +215,14 @@ for .Cm powerpc64 and with -.Fx 14.0 +.Fx 14.1 for .Cm amd64 . .Pp A .Nm manual page appeared in -.Fx 14.0 . +.Fx 14.1 . . .Sh AUTHOR .An Robert Clausecker Aq Mt fuz@FreeBSD.org diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5 --- a/stand/defaults/loader.conf.5 +++ b/stand/defaults/loader.conf.5 @@ -21,7 +21,7 @@ .\" 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 July 31, 2021 +.Dd December 20, 2023 .Dt LOADER.CONF 5 .Os .Sh NAME @@ -431,6 +431,7 @@ machine-specific settings for sites with a common loader.conf. .El .Sh SEE ALSO +.Xr kenv 1 , .Xr loader.conf.lua 5 , .Xr rc.conf 5 , .Xr boot 8 , diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -611,7 +611,7 @@ * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ -void +int cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { @@ -637,13 +637,15 @@ td->td_frame->tf_rip = (uintptr_t)entry; /* Return address sentinel value to stop stack unwinding. */ - suword32((void *)td->td_frame->tf_rsp, 0); + if (suword32((void *)td->td_frame->tf_rsp, 0) != 0) + return (EFAULT); /* Pass the argument to the entry point. */ - suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)), - (uint32_t)(uintptr_t)arg); - - return; + if (suword32( + (void *)(td->td_frame->tf_rsp + sizeof(int32_t)), + (uint32_t)(uintptr_t)arg) != 0) + return (EFAULT); + return (0); } #endif @@ -663,10 +665,13 @@ td->td_frame->tf_flags = TF_HASSEGS; /* Return address sentinel value to stop stack unwinding. */ - suword((void *)td->td_frame->tf_rsp, 0); + if (suword((void *)td->td_frame->tf_rsp, 0) != 0) + return (EFAULT); /* Pass the argument to the entry point. */ td->td_frame->tf_rdi = (register_t)arg; + + return (0); } int diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -260,8 +260,6 @@ int prot, void **cookie); void *vm_gpa_hold_global(struct vm *vm, vm_paddr_t gpa, size_t len, int prot, void **cookie); -void *vm_gpa_hold_global(struct vm *vm, vm_paddr_t gpa, size_t len, - int prot, void **cookie); void vm_gpa_release(void *cookie); bool vm_mem_allocated(struct vcpu *vcpu, vm_paddr_t gpa); diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -1037,54 +1037,79 @@ } static void -vm_iommu_modify(struct vm *vm, bool map) +vm_iommu_map(struct vm *vm) { - int i, sz; vm_paddr_t gpa, hpa; struct mem_map *mm; - void *vp, *cookie, *host_domain; + int i; - sz = PAGE_SIZE; - host_domain = iommu_host_domain(); + sx_assert(&vm->mem_segs_lock, SX_LOCKED); for (i = 0; i < VM_MAX_MEMMAPS; i++) { mm = &vm->mem_maps[i]; if (!sysmem_mapping(vm, mm)) continue; - if (map) { - KASSERT((mm->flags & VM_MEMMAP_F_IOMMU) == 0, - ("iommu map found invalid memmap %#lx/%#lx/%#x", - mm->gpa, mm->len, mm->flags)); - if ((mm->flags & VM_MEMMAP_F_WIRED) == 0) - continue; - mm->flags |= VM_MEMMAP_F_IOMMU; - } else { - if ((mm->flags & VM_MEMMAP_F_IOMMU) == 0) - continue; - mm->flags &= ~VM_MEMMAP_F_IOMMU; - KASSERT((mm->flags & VM_MEMMAP_F_WIRED) != 0, - ("iommu unmap found invalid memmap %#lx/%#lx/%#x", - mm->gpa, mm->len, mm->flags)); + KASSERT((mm->flags & VM_MEMMAP_F_IOMMU) == 0, + ("iommu map found invalid memmap %#lx/%#lx/%#x", + mm->gpa, mm->len, mm->flags)); + if ((mm->flags & VM_MEMMAP_F_WIRED) == 0) + continue; + mm->flags |= VM_MEMMAP_F_IOMMU; + + for (gpa = mm->gpa; gpa < mm->gpa + mm->len; gpa += PAGE_SIZE) { + hpa = pmap_extract(vmspace_pmap(vm->vmspace), gpa); + + /* + * All mappings in the vmm vmspace must be + * present since they are managed by vmm in this way. + * Because we are in pass-through mode, the + * mappings must also be wired. This implies + * that all pages must be mapped and wired, + * allowing to use pmap_extract() and avoiding the + * need to use vm_gpa_hold_global(). + * + * This could change if/when we start + * supporting page faults on IOMMU maps. + */ + KASSERT(vm_page_wired(PHYS_TO_VM_PAGE(hpa)), + ("vm_iommu_map: vm %p gpa %jx hpa %jx not wired", + vm, (uintmax_t)gpa, (uintmax_t)hpa)); + + iommu_create_mapping(vm->iommu, gpa, hpa, PAGE_SIZE); } + } - gpa = mm->gpa; - while (gpa < mm->gpa + mm->len) { - vp = vm_gpa_hold_global(vm, gpa, PAGE_SIZE, - VM_PROT_WRITE, &cookie); - KASSERT(vp != NULL, ("vm(%s) could not map gpa %#lx", - vm_name(vm), gpa)); + iommu_invalidate_tlb(iommu_host_domain()); +} + +static void +vm_iommu_unmap(struct vm *vm) +{ + vm_paddr_t gpa; + struct mem_map *mm; + int i; - vm_gpa_release(cookie); + sx_assert(&vm->mem_segs_lock, SX_LOCKED); - hpa = DMAP_TO_PHYS((uintptr_t)vp); - if (map) { - iommu_create_mapping(vm->iommu, gpa, hpa, sz); - } else { - iommu_remove_mapping(vm->iommu, gpa, sz); - } + for (i = 0; i < VM_MAX_MEMMAPS; i++) { + mm = &vm->mem_maps[i]; + if (!sysmem_mapping(vm, mm)) + continue; - gpa += PAGE_SIZE; + if ((mm->flags & VM_MEMMAP_F_IOMMU) == 0) + continue; + mm->flags &= ~VM_MEMMAP_F_IOMMU; + KASSERT((mm->flags & VM_MEMMAP_F_WIRED) != 0, + ("iommu unmap found invalid memmap %#lx/%#lx/%#x", + mm->gpa, mm->len, mm->flags)); + + for (gpa = mm->gpa; gpa < mm->gpa + mm->len; gpa += PAGE_SIZE) { + KASSERT(vm_page_wired(PHYS_TO_VM_PAGE(pmap_extract( + vmspace_pmap(vm->vmspace), gpa))), + ("vm_iommu_unmap: vm %p gpa %jx not wired", + vm, (uintmax_t)gpa)); + iommu_remove_mapping(vm->iommu, gpa, PAGE_SIZE); } } @@ -1092,15 +1117,9 @@ * Invalidate the cached translations associated with the domain * from which pages were removed. */ - if (map) - iommu_invalidate_tlb(host_domain); - else - iommu_invalidate_tlb(vm->iommu); + iommu_invalidate_tlb(vm->iommu); } -#define vm_iommu_unmap(vm) vm_iommu_modify((vm), false) -#define vm_iommu_map(vm) vm_iommu_modify((vm), true) - int vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func) { diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -629,10 +629,12 @@ p = (uint8_t *)vmrun->cpuset + sizeof(cpuset_t); - while (error == 0 && - p < (uint8_t *)vmrun->cpuset + + while (p < (uint8_t *)vmrun->cpuset + vmrun->cpusetsize) { - error = subyte(p++, 0); + if (subyte(p++, 0) != 0) { + error = EFAULT; + break; + } } } } diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -224,7 +224,7 @@ * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ -void +int cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { @@ -236,6 +236,7 @@ tf->tf_spsr = PSR_USR32_MODE; if ((register_t)entry & 1) tf->tf_spsr |= PSR_T; + return (0); } int diff --git a/sys/arm/nvidia/drm2/tegra_bo.c b/sys/arm/nvidia/drm2/tegra_bo.c --- a/sys/arm/nvidia/drm2/tegra_bo.c +++ b/sys/arm/nvidia/drm2/tegra_bo.c @@ -94,7 +94,7 @@ vm_page_t **ret_page) { vm_page_t m; - int tries, i; + int err, i, tries; vm_paddr_t low, high, boundary; low = 0; @@ -106,9 +106,12 @@ low, high, alignment, boundary, memattr); if (m == NULL) { if (tries < 3) { - if (!vm_page_reclaim_contig(0, npages, low, high, - alignment, boundary)) + err = vm_page_reclaim_contig(0, npages, low, high, + alignment, boundary); + if (err == ENOMEM) vm_wait(NULL); + else if (err != 0) + return (ENOMEM); tries++; goto retry; } diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c --- a/sys/arm64/arm64/vm_machdep.c +++ b/sys/arm64/arm64/vm_machdep.c @@ -205,7 +205,7 @@ * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ -void +int cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { @@ -224,6 +224,7 @@ tf->tf_x[0] = (register_t)arg; tf->tf_x[29] = 0; tf->tf_lr = 0; + return (0); } int diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c --- a/sys/cam/scsi/scsi_enc_ses.c +++ b/sys/cam/scsi/scsi_enc_ses.c @@ -2810,8 +2810,8 @@ } if (elmd->elm_desc_len > elmpriv->descr_len) elmd->elm_desc_len = elmpriv->descr_len; - copyout(elmpriv->descr, elmd->elm_desc_str, elmd->elm_desc_len); - return (0); + return (copyout(elmpriv->descr, elmd->elm_desc_str, + elmd->elm_desc_len)); } /** @@ -2827,7 +2827,7 @@ ses_get_elm_devnames(enc_softc_t *enc, encioc_elm_devnames_t *elmdn) { struct sbuf sb; - int len; + int error, len; len = elmdn->elm_names_size; if (len < 0) @@ -2839,10 +2839,13 @@ ses_elmdevname_callback, &sb); sbuf_finish(&sb); elmdn->elm_names_len = sbuf_len(&sb); - copyout(sbuf_data(&sb), elmdn->elm_devnames, elmdn->elm_names_len + 1); + error = copyout(sbuf_data(&sb), elmdn->elm_devnames, + elmdn->elm_names_len + 1); sbuf_delete(&sb); cam_periph_lock(enc->periph); - return (elmdn->elm_names_len > 0 ? 0 : ENODEV); + if (error == 0 && elmdn->elm_names_len == 0) + error = ENODEV; + return (error); } /** @@ -2921,9 +2924,9 @@ size = rsize; if (size > sstr->bufsiz) size = sstr->bufsiz; - copyout(str, sstr->buf, size); + ret = copyout(str, sstr->buf, size); sstr->bufsiz = rsize; - return (size == rsize ? 0 : ENOMEM); + return (ret != 0 ? ret : (size == rsize ? 0 : ENOMEM)); case ENCIOC_GETENCID: if (ses_cache->ses_nsubencs < 1) return (ENODEV); @@ -2935,9 +2938,9 @@ size = rsize; if (size > sstr->bufsiz) size = sstr->bufsiz; - copyout(str, sstr->buf, size); + ret = copyout(str, sstr->buf, size); sstr->bufsiz = rsize; - return (size == rsize ? 0 : ENOMEM); + return (ret != 0 ? ret : (size == rsize ? 0 : ENOMEM)); default: return (EINVAL); } diff --git a/sys/compat/freebsd32/freebsd32_capability.c b/sys/compat/freebsd32/freebsd32_capability.c --- a/sys/compat/freebsd32/freebsd32_capability.c +++ b/sys/compat/freebsd32/freebsd32_capability.c @@ -117,9 +117,10 @@ cmds = fdep->fde_ioctls; if (cmds32 != NULL && cmds != NULL) { for (i = 0; i < MIN(fdep->fde_nioctls, maxcmds); i++) { - error = suword32(&cmds32[i], cmds[i]); - if (error != 0) + if (suword32(&cmds32[i], cmds[i]) != 0) { + error = EFAULT; goto out; + } } } if (fdep->fde_nioctls == -1) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -2195,7 +2195,7 @@ fdrop(fp, td); if (uap->sbytes != NULL) - copyout(&sbytes, uap->sbytes, sizeof(off_t)); + (void)copyout(&sbytes, uap->sbytes, sizeof(off_t)); out: if (hdr_uio) @@ -2675,9 +2675,9 @@ uap->new, uap->newlen, &j, SCTL_MASK32); if (error) return (error); - if (uap->oldlenp) - suword32(uap->oldlenp, j); - return (0); + if (uap->oldlenp != NULL && suword32(uap->oldlenp, j) != 0) + error = EFAULT; + return (error); } int @@ -2700,9 +2700,8 @@ &oldlen, uap->new, uap->newlen, &rv, SCTL_MASK32, 1); if (error != 0) return (error); - if (uap->oldlenp != NULL) - error = suword32(uap->oldlenp, rv); - + if (uap->oldlenp != NULL && suword32(uap->oldlenp, rv) != 0) + error = EFAULT; return (error); } diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h b/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h --- a/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h +++ b/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h @@ -37,6 +37,8 @@ uint32_t data; }; +#define acpi_dev_present(...) lkpi_acpi_dev_present(__VA_ARGS__) + ACPI_HANDLE bsd_acpi_get_handle(device_t bsddev); bool acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs); @@ -46,5 +48,7 @@ int register_acpi_notifier(struct notifier_block *nb); int unregister_acpi_notifier(struct notifier_block *nb); uint32_t acpi_target_system_state(void); +bool lkpi_acpi_dev_present(const char *hid, const char *uid, + int64_t hrv); #endif /* _LINUXKPI_ACPI_ACPI_BUS_H_ */ diff --git a/sys/compat/linuxkpi/common/include/acpi/video.h b/sys/compat/linuxkpi/common/include/acpi/video.h --- a/sys/compat/linuxkpi/common/include/acpi/video.h +++ b/sys/compat/linuxkpi/common/include/acpi/video.h @@ -29,6 +29,7 @@ #ifndef _LINUXKPI_ACPI_VIDEO_H_ #define _LINUXKPI_ACPI_VIDEO_H_ +#include #include #define ACPI_VIDEO_CLASS "video" @@ -47,4 +48,15 @@ { } +static inline void +acpi_video_register_backlight(void) +{ +} + +static inline bool +acpi_video_backlight_use_native(void) +{ + return (true); +} + #endif /* _LINUXKPI_ACPI_VIDEO_H_ */ diff --git a/sys/compat/linuxkpi/common/include/asm/hypervisor.h b/sys/compat/linuxkpi/common/include/asm/hypervisor.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/asm/hypervisor.h @@ -0,0 +1,19 @@ +/* Public domain. */ + +#ifndef _LINUXKPI_ASM_HYPERVISOR_H +#define _LINUXKPI_ASM_HYPERVISOR_H + +#if defined(__i386__) || defined(__amd64__) + +#define X86_HYPER_NATIVE 1 +#define X86_HYPER_MS_HYPERV 2 + +static inline bool +hypervisor_is_type(int type) +{ + return (type == X86_HYPER_NATIVE); +} + +#endif + +#endif diff --git a/sys/compat/linuxkpi/common/include/asm/processor.h b/sys/compat/linuxkpi/common/include/asm/processor.h --- a/sys/compat/linuxkpi/common/include/asm/processor.h +++ b/sys/compat/linuxkpi/common/include/asm/processor.h @@ -33,15 +33,28 @@ #include #if defined(__i386__) || defined(__amd64__) +#define X86_VENDOR_INTEL 0 +#define X86_VENDOR_CYRIX 1 +#define X86_VENDOR_AMD 2 +#define X86_VENDOR_UMC 3 +#define X86_VENDOR_CENTAUR 5 +#define X86_VENDOR_TRANSMETA 7 +#define X86_VENDOR_NSC 8 +#define X86_VENDOR_HYGON 9 +#define X86_VENDOR_NUM 12 + +#define X86_VENDOR_UNKNOWN 0xff + struct cpuinfo_x86 { uint8_t x86; uint8_t x86_model; uint16_t x86_clflush_size; uint16_t x86_max_cores; + uint8_t x86_vendor; }; extern struct cpuinfo_x86 boot_cpu_data; -extern struct cpuinfo_x86 __cpu_data[]; +extern struct cpuinfo_x86 *__cpu_data; #define cpu_data(cpu) __cpu_data[cpu] #endif diff --git a/sys/compat/linuxkpi/common/include/linux/apple-gmux.h b/sys/compat/linuxkpi/common/include/linux/apple-gmux.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/apple-gmux.h @@ -0,0 +1,12 @@ +/* Public domain. */ + +#ifndef _LINUXKPI_LINUX_APPLE_GMUX_H +#define _LINUXKPI_LINUX_APPLE_GMUX_H + +static inline bool +apple_gmux_detect(void *a, void *b) +{ + return false; +} + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/bitmap.h b/sys/compat/linuxkpi/common/include/linux/bitmap.h --- a/sys/compat/linuxkpi/common/include/linux/bitmap.h +++ b/sys/compat/linuxkpi/common/include/linux/bitmap.h @@ -264,6 +264,27 @@ return (1); } +static inline bool +bitmap_intersects(const unsigned long *pa, const unsigned long *pb, + unsigned size) +{ + const unsigned end = BIT_WORD(size); + const unsigned tail = size & (BITS_PER_LONG - 1); + unsigned i; + + for (i = 0; i != end; i++) + if (pa[i] & pb[i]) + return (true); + + if (tail) { + const unsigned long mask = BITMAP_LAST_WORD_MASK(tail); + + if (pa[end] & pb[end] & mask) + return (true); + } + return (false); +} + static inline void bitmap_complement(unsigned long *dst, const unsigned long *src, const unsigned int size) @@ -306,6 +327,29 @@ dst[end - 1] &= (uint32_t)(UINT_MAX >> (32 - (size % 32))); } +static inline void +bitmap_from_arr32(unsigned long *dst, const uint32_t *src, + unsigned int size) +{ + const unsigned int end = BIT_WORD(size); + const unsigned int tail = size & (BITS_PER_LONG - 1); + +#ifdef __LP64__ + const unsigned int end32 = howmany(size, 32); + unsigned int i = 0; + + while (i < end32) { + dst[i++/2] = (unsigned long) *(src++); + if (i < end32) + dst[i++/2] |= ((unsigned long) *(src++)) << 32; + } +#else + bitmap_copy(dst, (const unsigned long *)src, size); +#endif + if ((size % BITS_PER_LONG) != 0) + dst[end] &= BITMAP_LAST_WORD_MASK(tail); +} + static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, const unsigned long *src2, const unsigned int size) @@ -350,6 +394,40 @@ dst[i] = src1[i] ^ src2[i]; } +static inline void +bitmap_shift_right(unsigned long *dst, const unsigned long *src, + unsigned int shift, unsigned int size) +{ + const unsigned int end = BITS_TO_LONGS(size); + const unsigned int tail = size & (BITS_PER_LONG - 1); + const unsigned long mask = BITMAP_LAST_WORD_MASK(tail); + const unsigned int off = BIT_WORD(shift); + const unsigned int rem = shift & (BITS_PER_LONG - 1); + unsigned long left, right; + unsigned int i, srcpos; + + for (i = 0, srcpos = off; srcpos < end; i++, srcpos++) { + right = src[srcpos]; + left = 0; + + if (srcpos == end - 1) + right &= mask; + + if (rem != 0) { + right >>= rem; + if (srcpos + 1 < end) { + left = src[srcpos + 1]; + if (srcpos + 1 == end - 1) + left &= mask; + left <<= (BITS_PER_LONG - rem); + } + } + dst[i] = left | right; + } + if (off != 0) + memset(dst + end - off, 0, off * sizeof(unsigned long)); +} + static inline unsigned long * bitmap_alloc(unsigned int size, gfp_t flags) { diff --git a/sys/compat/linuxkpi/common/include/linux/build_bug.h b/sys/compat/linuxkpi/common/include/linux/build_bug.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/build_bug.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2017 Mark Johnston + * Copyright (c) 2018 Johannes Lundberg + * Copyright (c) 2021 The FreeBSD Foundation + * Copyright (c) 2021 Vladimir Kondratyev + * Copyright (c) 2023 Serenity Cyber Security, LLC + * + * Portions of this software were developed by Bjoern A. Zeeb + * under sponsorship from the FreeBSD Foundation. + * + * 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 unmodified, 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 ``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 BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUXKPI_LINUX_BUILD_BUG_H_ +#define _LINUXKPI_LINUX_BUILD_BUG_H_ + +#include + +#include + +/* + * BUILD_BUG_ON() can happen inside functions where _Static_assert() does not + * seem to work. Use old-schoold-ish CTASSERT from before commit + * a3085588a88fa58eb5b1eaae471999e1995a29cf but also make sure we do not + * end up with an unused typedef or variable. The compiler should optimise + * it away entirely. + */ +#define _O_CTASSERT(x) _O__CTASSERT(x, __LINE__) +#define _O__CTASSERT(x, y) _O___CTASSERT(x, y) +#define _O___CTASSERT(x, y) while (0) { \ + typedef char __assert_line_ ## y[(x) ? 1 : -1]; \ + __assert_line_ ## y _x; \ + _x[0] = '\0'; \ +} + +#define BUILD_BUG() do { CTASSERT(0); } while (0) +#define BUILD_BUG_ON(x) do { _O_CTASSERT(!(x)) } while (0) +#define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x) +#define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x)) +#define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); } +#define BUILD_BUG_ON_ZERO(x) ((int)sizeof(struct { int:-((x) != 0); })) + +#define static_assert(x, ...) __static_assert(x, ##__VA_ARGS__, #x) +#define __static_assert(x, msg, ...) _Static_assert(x, msg) + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/compat.h b/sys/compat/linuxkpi/common/include/linux/compat.h --- a/sys/compat/linuxkpi/common/include/linux/compat.h +++ b/sys/compat/linuxkpi/common/include/linux/compat.h @@ -40,6 +40,7 @@ extern int linux_alloc_current(struct thread *, int flags); extern void linux_free_current(struct task_struct *); extern struct domainset *linux_get_vm_domain_set(int node); +extern int linux_set_fpu_ctx(struct task_struct *); static inline void linux_set_current(struct thread *td) diff --git a/sys/compat/linuxkpi/common/include/linux/string_helpers.h b/sys/compat/linuxkpi/common/include/linux/container_of.h copy from sys/compat/linuxkpi/common/include/linux/string_helpers.h copy to sys/compat/linuxkpi/common/include/linux/container_of.h --- a/sys/compat/linuxkpi/common/include/linux/string_helpers.h +++ b/sys/compat/linuxkpi/common/include/linux/container_of.h @@ -1,7 +1,9 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2023 Jean-Sébastien Pédron + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * Copyright (c) 2017 Matt Macy + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,18 +27,20 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _LINUXKPI_LINUX_STRING_HELPERS_H_ -#define _LINUXKPI_LINUX_STRING_HELPERS_H_ +#ifndef _LINUXKPI_LINUX_CONTAINER_OF_H +#define _LINUXKPI_LINUX_CONTAINER_OF_H + +#include + +#include +#include -#include +#define container_of(ptr, type, member) \ +({ \ + const __typeof(((type *)0)->member) *__p = (ptr); \ + (type *)((uintptr_t)__p - offsetof(type, member)); \ +}) -static inline const char * -str_yes_no(bool value) -{ - if (value) - return "yes"; - else - return "no"; -} +#define typeof_member(type, member) __typeof(((type *)0)->member) -#endif /* _LINUXKPI_LINUX_STRING_HELPERS_H_ */ +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h --- a/sys/compat/linuxkpi/common/include/linux/device.h +++ b/sys/compat/linuxkpi/common/include/linux/device.h @@ -236,6 +236,14 @@ } \ } while (0) +#define dev_dbg_once(dev, ...) do { \ + static bool __dev_dbg_once; \ + if (!__dev_dbg_once) { \ + __dev_dbg_once = 1; \ + dev_dbg(dev, __VA_ARGS__); \ + } \ +} while (0) + #define dev_err_ratelimited(dev, ...) do { \ static linux_ratelimit_t __ratelimited; \ if (linux_ratelimited(&__ratelimited)) \ diff --git a/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h b/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUXKPI_LINUX_DYNAMIC_DEBUG_H +#define _LINUXKPI_LINUX_DYNAMIC_DEBUG_H + +#define DECLARE_DYNDBG_CLASSMAP(a, b, c, ...) + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/idr.h b/sys/compat/linuxkpi/common/include/linux/idr.h --- a/sys/compat/linuxkpi/common/include/linux/idr.h +++ b/sys/compat/linuxkpi/common/include/linux/idr.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -131,6 +132,12 @@ return (ida_get_new_above(ida, 0, p_id)); } +static inline int +ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp) +{ + return (ida_simple_get(ida, min, UINT_MAX, gfp)); +} + static inline int ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp) { diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h --- a/sys/compat/linuxkpi/common/include/linux/interrupt.h +++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h @@ -40,7 +40,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *); -#define IRQF_SHARED RF_SHAREABLE +#define IRQF_SHARED 0x0004 /* Historically */ #define IRQF_NOBALANCING 0 #define IRQ_DISABLE_UNLAZY 0 diff --git a/sys/compat/linuxkpi/common/include/linux/io.h b/sys/compat/linuxkpi/common/include/linux/io.h --- a/sys/compat/linuxkpi/common/include/linux/io.h +++ b/sys/compat/linuxkpi/common/include/linux/io.h @@ -35,6 +35,7 @@ #include #include +#include #include #if !defined(__arm__) #include @@ -349,6 +350,16 @@ } #define ioread32be(addr) ioread32be(addr) +#ifdef __LP64__ +#undef ioread64 +static inline uint64_t +ioread64(const volatile void *addr) +{ + return (readq(addr)); +} +#define ioread64(addr) ioread64(addr) +#endif + #undef iowrite8 static inline void iowrite8(uint8_t v, volatile void *addr) @@ -520,6 +531,8 @@ iounmap(addr); } +#define IOMEM_ERR_PTR(err) (void __iomem *)ERR_PTR(err) + #define __MTRR_ID_BASE 1 int lkpi_arch_phys_wc_add(unsigned long, unsigned long); void lkpi_arch_phys_wc_del(int); diff --git a/sys/compat/linuxkpi/common/include/acpi/video.h b/sys/compat/linuxkpi/common/include/linux/ioport.h copy from sys/compat/linuxkpi/common/include/acpi/video.h copy to sys/compat/linuxkpi/common/include/linux/ioport.h --- a/sys/compat/linuxkpi/common/include/acpi/video.h +++ b/sys/compat/linuxkpi/common/include/linux/ioport.h @@ -1,17 +1,16 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2020 Vladimir Kondratyev + * Copyright (c) 2023 Serenity Cyber Security, LLC. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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. + * 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 @@ -26,25 +25,33 @@ * SUCH DAMAGE. */ -#ifndef _LINUXKPI_ACPI_VIDEO_H_ -#define _LINUXKPI_ACPI_VIDEO_H_ +#ifndef _LINUXKPI_LINUX_IOPORT_H +#define _LINUXKPI_LINUX_IOPORT_H -#include +#include +#include -#define ACPI_VIDEO_CLASS "video" +#define DEFINE_RES_MEM(_start, _size) \ + (struct resource) { \ + .start = (_start), \ + .end = (_start) + (_size) - 1, \ + } -#define ACPI_VIDEO_NOTIFY_PROBE 0x81 +struct resource { + resource_size_t start; + resource_size_t end; +}; -static inline int -acpi_video_register(void) +static inline resource_size_t +resource_size(const struct resource *r) { - - return (-ENODEV); + return (r->end - r->start + 1); } -static inline void -acpi_video_unregister(void) +static inline bool +resource_contains(struct resource *a, struct resource *b) { + return (a->start <= b->start && a->end >= b->end); } -#endif /* _LINUXKPI_ACPI_VIDEO_H_ */ +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/iosys-map.h b/sys/compat/linuxkpi/common/include/linux/iosys-map.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/iosys-map.h @@ -0,0 +1,161 @@ +/* Public domain. */ + +#ifndef _LINUXKPI_LINUX_IOSYS_MAP_H +#define _LINUXKPI_LINUX_IOSYS_MAP_H + +#include +#include + +struct iosys_map { + union { + void *vaddr_iomem; + void *vaddr; + }; + bool is_iomem; +#ifdef __OpenBSD__ + bus_space_handle_t bsh; + bus_size_t size; +#endif +}; + +#define IOSYS_MAP_INIT_OFFSET(_ism_src_p, _off) ({ \ + struct iosys_map ism_dst = *(_ism_src_p); \ + iosys_map_incr(&ism_dst, _off); \ + ism_dst; \ +}) + +static inline void +iosys_map_incr(struct iosys_map *ism, size_t n) +{ + if (ism->is_iomem) + ism->vaddr_iomem += n; + else + ism->vaddr += n; +} + +static inline void +iosys_map_memcpy_to(struct iosys_map *ism, size_t off, const void *src, + size_t len) +{ + if (ism->is_iomem) + memcpy_toio(ism->vaddr_iomem + off, src, len); + else + memcpy(ism->vaddr + off, src, len); +} + +static inline bool +iosys_map_is_null(const struct iosys_map *ism) +{ + if (ism->is_iomem) + return (ism->vaddr_iomem == NULL); + else + return (ism->vaddr == NULL); +} + +static inline bool +iosys_map_is_set(const struct iosys_map *ism) +{ + if (ism->is_iomem) + return (ism->vaddr_iomem != NULL); + else + return (ism->vaddr != NULL); +} + +static inline bool +iosys_map_is_equal(const struct iosys_map *ism_a, + const struct iosys_map *ism_b) +{ + if (ism_a->is_iomem != ism_b->is_iomem) + return (false); + + if (ism_a->is_iomem) + return (ism_a->vaddr_iomem == ism_b->vaddr_iomem); + else + return (ism_a->vaddr == ism_b->vaddr); +} + +static inline void +iosys_map_clear(struct iosys_map *ism) +{ + if (ism->is_iomem) { + ism->vaddr_iomem = NULL; + ism->is_iomem = false; + } else { + ism->vaddr = NULL; + } +} + +static inline void +iosys_map_set_vaddr_iomem(struct iosys_map *ism, void *addr) +{ + ism->vaddr_iomem = addr; + ism->is_iomem = true; +} + +static inline void +iosys_map_set_vaddr(struct iosys_map *ism, void *addr) +{ + ism->vaddr = addr; + ism->is_iomem = false; +} + +static inline void +iosys_map_memset(struct iosys_map *ism, size_t off, int value, size_t len) +{ + if (ism->is_iomem) + memset_io(ism->vaddr_iomem + off, value, len); + else + memset(ism->vaddr + off, value, len); +} + +#ifdef __LP64__ +#define _iosys_map_readq(_addr) readq(_addr) +#define _iosys_map_writeq(_val, _addr) writeq(_val, _addr) +#else +#define _iosys_map_readq(_addr) ({ \ + uint64_t val; \ + memcpy_fromio(&val, _addr, sizeof(uint64_t)); \ + val; \ +}) +#define _iosys_map_writeq(_val, _addr) \ + memcpy_toio(_addr, &(_val), sizeof(uint64_t)) +#endif + +#define iosys_map_rd(_ism, _off, _type) ({ \ + _type val; \ + if ((_ism)->is_iomem) { \ + void *addr = (_ism)->vaddr_iomem + (_off); \ + val = _Generic(val, \ + uint8_t : readb(addr), \ + uint16_t: readw(addr), \ + uint32_t: readl(addr), \ + uint64_t: _iosys_map_readq(addr)); \ + } else \ + val = READ_ONCE(*(_type *)((_ism)->vaddr + (_off))); \ + val; \ +}) +#define iosys_map_wr(_ism, _off, _type, _val) ({ \ + _type val = (_val); \ + if ((_ism)->is_iomem) { \ + void *addr = (_ism)->vaddr_iomem + (_off); \ + _Generic(val, \ + uint8_t : writeb(val, addr), \ + uint16_t: writew(val, addr), \ + uint32_t: writel(val, addr), \ + uint64_t: _iosys_map_writeq(val, addr)); \ + } else \ + WRITE_ONCE(*(_type *)((_ism)->vaddr + (_off)), val); \ +}) + +#define iosys_map_rd_field(_ism, _off, _type, _field) ({ \ + _type *s; \ + iosys_map_rd(_ism, (_off) + offsetof(_type, _field), \ + __typeof(s->_field)); \ +}) +#define iosys_map_wr_field(_ism, _off, _type, _field, _val) ({ \ + _type *s; \ + iosys_map_wr(_ism, (_off) + offsetof(_type, _field), \ + __typeof(s->_field), _val); \ +}) + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/irqdomain.h b/sys/compat/linuxkpi/common/include/linux/irqdomain.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/irqdomain.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef _LINUXKPI_LINUX_IRQDOMAIN_H +#define _LINUXKPI_LINUX_IRQDOMAIN_H + +#include +#include +#include + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h --- a/sys/compat/linuxkpi/common/include/linux/kernel.h +++ b/sys/compat/linuxkpi/common/include/linux/kernel.h @@ -41,7 +41,9 @@ #include #include +#include #include +#include #include #include #include @@ -90,28 +92,6 @@ #define S64_C(x) x ## LL #define U64_C(x) x ## ULL -/* - * BUILD_BUG_ON() can happen inside functions where _Static_assert() does not - * seem to work. Use old-schoold-ish CTASSERT from before commit - * a3085588a88fa58eb5b1eaae471999e1995a29cf but also make sure we do not - * end up with an unused typedef or variable. The compiler should optimise - * it away entirely. - */ -#define _O_CTASSERT(x) _O__CTASSERT(x, __LINE__) -#define _O__CTASSERT(x, y) _O___CTASSERT(x, y) -#define _O___CTASSERT(x, y) while (0) { \ - typedef char __unused __assert_line_ ## y[(x) ? 1 : -1]; \ - __assert_line_ ## y _x; \ - _x[0] = '\0'; \ -} - -#define BUILD_BUG() do { CTASSERT(0); } while (0) -#define BUILD_BUG_ON(x) do { _O_CTASSERT(!(x)) } while (0) -#define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x) -#define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x)) -#define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); } -#define BUILD_BUG_ON_ZERO(x) ((int)sizeof(struct { int:-((x) != 0); })) - #define BUG() panic("BUG at %s:%d", __FILE__, __LINE__) #define BUG_ON(cond) do { \ if (cond) { \ @@ -294,12 +274,6 @@ }) #endif -#define container_of(ptr, type, member) \ -({ \ - const __typeof(((type *)0)->member) *__p = (ptr); \ - (type *)((uintptr_t)__p - offsetof(type, member)); \ -}) - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define u64_to_user_ptr(val) ((void *)(uintptr_t)(val)) @@ -572,8 +546,6 @@ #define offsetofend(t, m) \ (offsetof(t, m) + sizeof((((t *)0)->m))) -#define typeof_member(s, e) typeof(((s *)0)->e) - #define clamp_t(type, _x, min, max) min_t(type, max_t(type, _x, min), max) #define clamp(x, lo, hi) min( max(x,lo), hi) #define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi) diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h --- a/sys/compat/linuxkpi/common/include/linux/kobject.h +++ b/sys/compat/linuxkpi/common/include/linux/kobject.h @@ -36,6 +36,8 @@ #include #include #include +#include +#include struct kobject; struct kset; diff --git a/sys/compat/linuxkpi/common/include/linux/ktime.h b/sys/compat/linuxkpi/common/include/linux/ktime.h --- a/sys/compat/linuxkpi/common/include/linux/ktime.h +++ b/sys/compat/linuxkpi/common/include/linux/ktime.h @@ -262,4 +262,13 @@ return (ktime_to_ns(timespec_to_ktime(ts))); } +static inline uint64_t +ktime_get_raw_fast_ns(void) +{ + struct timespec ts; + + getnanouptime(&ts); + return (ktime_to_ns(timespec_to_ktime(ts))); +} + #endif /* _LINUXKPI_LINUX_KTIME_H */ diff --git a/sys/compat/linuxkpi/common/include/linux/list.h b/sys/compat/linuxkpi/common/include/linux/list.h --- a/sys/compat/linuxkpi/common/include/linux/list.h +++ b/sys/compat/linuxkpi/common/include/linux/list.h @@ -144,7 +144,7 @@ } static inline void -linux_list_add(struct list_head *new, struct list_head *prev, +__list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { @@ -238,14 +238,14 @@ list_add(struct list_head *new, struct list_head *head) { - linux_list_add(new, head, head->next); + __list_add(new, head, head->next); } static inline void list_add_tail(struct list_head *new, struct list_head *head) { - linux_list_add(new, head->prev, head); + __list_add(new, head->prev, head); } static inline void diff --git a/sys/compat/linuxkpi/common/include/acpi/video.h b/sys/compat/linuxkpi/common/include/linux/of.h copy from sys/compat/linuxkpi/common/include/acpi/video.h copy to sys/compat/linuxkpi/common/include/linux/of.h --- a/sys/compat/linuxkpi/common/include/acpi/video.h +++ b/sys/compat/linuxkpi/common/include/linux/of.h @@ -1,17 +1,16 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2020 Vladimir Kondratyev + * Copyright (c) 2023 Serenity Cyber Security, LLC. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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. + * 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 @@ -26,25 +25,9 @@ * SUCH DAMAGE. */ -#ifndef _LINUXKPI_ACPI_VIDEO_H_ -#define _LINUXKPI_ACPI_VIDEO_H_ +#ifndef _LINUXKPI_LINUX_OF_H +#define _LINUXKPI_LINUX_OF_H -#include +#include -#define ACPI_VIDEO_CLASS "video" - -#define ACPI_VIDEO_NOTIFY_PROBE 0x81 - -static inline int -acpi_video_register(void) -{ - - return (-ENODEV); -} - -static inline void -acpi_video_unregister(void) -{ -} - -#endif /* _LINUXKPI_ACPI_VIDEO_H_ */ +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -306,10 +305,16 @@ struct pci_msi_desc pci; }; +struct msix_entry { + int entry; + int vector; +}; + /* * If we find drivers accessing this from multiple KPIs we may have to * refcount objects of this structure. */ +struct resource; struct pci_mmio_region { TAILQ_ENTRY(pci_mmio_region) next; struct resource *res; @@ -342,36 +347,35 @@ size_t romlen; struct msi_desc **msi_desc; char *path_name; + spinlock_t pcie_cap_lock; TAILQ_HEAD(, pci_mmio_region) mmio; }; -/* We need some meta-struct to keep track of these for devres. */ -struct pci_devres { - bool enable_io; - /* PCIR_MAX_BAR_0 + 1 = 6 => BIT(0..5). */ - uint8_t region_mask; - struct resource *region_table[PCIR_MAX_BAR_0 + 1]; /* Not needed. */ -}; -struct pcim_iomap_devres { - void *mmio_table[PCIR_MAX_BAR_0 + 1]; - struct resource *res_table[PCIR_MAX_BAR_0 + 1]; -}; - int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name); int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv, unsigned int flags); bool pci_device_is_present(struct pci_dev *pdev); +int linuxkpi_pcim_enable_device(struct pci_dev *pdev); +void __iomem **linuxkpi_pcim_iomap_table(struct pci_dev *pdev); +void *linuxkpi_pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size); +void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res); +int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, + const char *name); +int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name); +void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar); +void linuxkpi_pci_release_regions(struct pci_dev *pdev); +int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, + int nreq); + /* Internal helper function(s). */ struct pci_dev *lkpinew_pci_dev(device_t); -struct pci_devres *lkpi_pci_devres_get_alloc(struct pci_dev *pdev); void lkpi_pci_devres_release(struct device *, void *); -struct resource *_lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size); -struct pcim_iomap_devres *lkpi_pcim_iomap_devres_find(struct pci_dev *pdev); -void lkpi_pcim_iomap_table_release(struct device *, void *); struct pci_dev *lkpi_pci_get_device(uint16_t, uint16_t, struct pci_dev *); struct msi_desc *lkpi_pci_msi_desc_alloc(int); +struct device *lkpi_pci_find_irq_dev(unsigned int irq); +int _lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec); static inline bool dev_is_pci(struct device *dev) @@ -395,56 +399,6 @@ return (SYS_RES_MEMORY); } -struct resource_list_entry *linux_pci_reserve_bar(struct pci_dev *pdev, - struct resource_list *rl, int type, int rid); - -static inline struct resource_list_entry * -linux_pci_get_rle(struct pci_dev *pdev, int type, int rid, bool reserve_bar) -{ - struct pci_devinfo *dinfo; - struct resource_list *rl; - struct resource_list_entry *rle; - - dinfo = device_get_ivars(pdev->dev.bsddev); - rl = &dinfo->resources; - rle = resource_list_find(rl, type, rid); - /* Reserve resources for this BAR if needed. */ - if (rle == NULL && reserve_bar) - rle = linux_pci_reserve_bar(pdev, rl, type, rid); - return (rle); -} - -static inline struct resource_list_entry * -linux_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve) -{ - int type; - - type = pci_resource_type(pdev, bar); - if (type < 0) - return (NULL); - bar = PCIR_BAR(bar); - return (linux_pci_get_rle(pdev, type, bar, reserve)); -} - -static inline struct device * -linux_pci_find_irq_dev(unsigned int irq) -{ - struct pci_dev *pdev; - struct device *found; - - found = NULL; - spin_lock(&pci_lock); - list_for_each_entry(pdev, &pci_devices, links) { - if (irq == pdev->dev.irq || - (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) { - found = &pdev->dev; - break; - } - } - spin_unlock(&pci_lock); - return (found); -} - /* * All drivers just seem to want to inspect the type not flags. */ @@ -578,73 +532,10 @@ return (pdev->bus->self); } -static inline struct pci_devres * -lkpi_pci_devres_find(struct pci_dev *pdev) -{ - - if (!pdev->managed) - return (NULL); - - return (lkpi_pci_devres_get_alloc(pdev)); -} - -static inline void -pci_release_region(struct pci_dev *pdev, int bar) -{ - struct resource_list_entry *rle; - struct pci_devres *dr; - struct pci_mmio_region *mmio, *p; - - if ((rle = linux_pci_get_bar(pdev, bar, false)) == NULL) - return; - - /* - * As we implicitly track the requests we also need to clear them on - * release. Do clear before resource release. - */ - dr = lkpi_pci_devres_find(pdev); - if (dr != NULL) { - KASSERT(dr->region_table[bar] == rle->res, ("%s: pdev %p bar %d" - " region_table res %p != rel->res %p\n", __func__, pdev, - bar, dr->region_table[bar], rle->res)); - dr->region_table[bar] = NULL; - dr->region_mask &= ~(1 << bar); - } - - TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { - if (rle->res != (void *)rman_get_bushandle(mmio->res)) - continue; - TAILQ_REMOVE(&pdev->mmio, mmio, next); - free(mmio, M_DEVBUF); - } - - bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res); -} - -static inline void -pci_release_regions(struct pci_dev *pdev) -{ - int i; - - for (i = 0; i <= PCIR_MAX_BAR_0; i++) - pci_release_region(pdev, i); -} - -static inline int -pci_request_regions(struct pci_dev *pdev, const char *res_name) -{ - int error; - int i; - - for (i = 0; i <= PCIR_MAX_BAR_0; i++) { - error = pci_request_region(pdev, i, res_name); - if (error && error != -ENODEV) { - pci_release_regions(pdev); - return (error); - } - } - return (0); -} +#define pci_release_region(pdev, bar) linuxkpi_pci_release_region(pdev, bar) +#define pci_release_regions(pdev) linuxkpi_pci_release_regions(pdev) +#define pci_request_regions(pdev, res_name) \ + linuxkpi_pci_request_regions(pdev, res_name) static inline void lkpi_pci_disable_msix(struct pci_dev *pdev) @@ -655,7 +546,7 @@ /* * The MSIX IRQ numbers associated with this PCI device are no * longer valid and might be re-assigned. Make sure - * linux_pci_find_irq_dev() does no longer see them by + * lkpi_pci_find_irq_dev() does no longer see them by * resetting their references to zero: */ pdev->dev.irq_start = 0; @@ -813,11 +704,6 @@ #define pci_register_driver(pdrv) linux_pci_register_driver(pdrv) #define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv) -struct msix_entry { - int entry; - int vector; -}; - /* * Enable msix, positive errors indicate actual number of available * vectors. Negative errors are failures. @@ -825,42 +711,7 @@ * NB: define added to prevent this definition of pci_enable_msix from * clashing with the native FreeBSD version. */ -#define pci_enable_msix(...) \ - linux_pci_enable_msix(__VA_ARGS__) - -static inline int -pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq) -{ - struct resource_list_entry *rle; - int error; - int avail; - int i; - - avail = pci_msix_count(pdev->dev.bsddev); - if (avail < nreq) { - if (avail == 0) - return -EINVAL; - return avail; - } - avail = nreq; - if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0) - return error; - /* - * Handle case where "pci_alloc_msix()" may allocate less - * interrupts than available and return with no error: - */ - if (avail < nreq) { - pci_release_msi(pdev->dev.bsddev); - return avail; - } - rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false); - pdev->dev.irq_start = rle->start; - pdev->dev.irq_end = rle->start + avail; - for (i = 0; i < nreq; i++) - entries[i].vector = pdev->dev.irq_start + i; - pdev->msix_enabled = true; - return (0); -} +#define pci_enable_msix(...) linuxkpi_pci_enable_msix(__VA_ARGS__) #define pci_enable_msix_range(...) \ linux_pci_enable_msix_range(__VA_ARGS__) @@ -891,38 +742,6 @@ #define pci_enable_msi(pdev) \ linux_pci_enable_msi(pdev) -static inline int -_lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec) -{ - struct resource_list_entry *rle; - int error; - int nvec; - - if (maxvec < minvec) - return (-EINVAL); - - nvec = pci_msi_count(pdev->dev.bsddev); - if (nvec < 1 || nvec < minvec) - return (-ENOSPC); - - nvec = min(nvec, maxvec); - if ((error = -pci_alloc_msi(pdev->dev.bsddev, &nvec)) != 0) - return error; - - /* Native PCI might only ever ask for 32 vectors. */ - if (nvec < minvec) { - pci_release_msi(pdev->dev.bsddev); - return (-ENOSPC); - } - - rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false); - pdev->dev.irq_start = rle->start; - pdev->dev.irq_end = rle->start + nvec; - pdev->irq = rle->start; - pdev->msi_enabled = true; - return (0); -} - static inline int pci_enable_msi(struct pci_dev *pdev) { @@ -946,35 +765,9 @@ { } -static inline void * -pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size) -{ - struct resource *res; - - res = _lkpi_pci_iomap(pdev, mmio_bar, mmio_size); - if (res == NULL) - return (NULL); - /* This is a FreeBSD extension so we can use bus_*(). */ - if (pdev->want_iomap_res) - return (res); - return ((void *)rman_get_bushandle(res)); -} - -static inline void -pci_iounmap(struct pci_dev *pdev, void *res) -{ - struct pci_mmio_region *mmio, *p; - - TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { - if (res != (void *)rman_get_bushandle(mmio->res)) - continue; - bus_release_resource(pdev->dev.bsddev, - mmio->type, mmio->rid, mmio->res); - TAILQ_REMOVE(&pdev->mmio, mmio, next); - free(mmio, M_DEVBUF); - return; - } -} +#define pci_iomap(pdev, mmio_bar, mmio_size) \ + linuxkpi_pci_iomap(pdev, mmio_bar, mmio_size) +#define pci_iounmap(pdev, res) linuxkpi_pci_iounmap(pdev, res) static inline void lkpi_pci_save_state(struct pci_dev *pdev) @@ -1220,35 +1013,38 @@ } static inline int -pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val) +pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, + uint16_t clear, uint16_t set) { int error; uint16_t v; + if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL) + spin_lock(&dev->pcie_cap_lock); + error = pcie_capability_read_word(dev, pos, &v); - if (error != 0) - return (error); + if (error == 0) { + v &= ~clear; + v |= set; + error = pcie_capability_write_word(dev, pos, v); + } - v |= val; + if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL) + spin_unlock(&dev->pcie_cap_lock); - error = pcie_capability_write_word(dev, pos, v); return (error); } static inline int -pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val) +pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val) { - int error; - uint16_t v; - - error = pcie_capability_read_word(dev, pos, &v); - if (error != 0) - return (error); - - v &= ~val; + return (pcie_capability_clear_and_set_word(dev, pos, 0, val)); +} - error = pcie_capability_write_word(dev, pos, v); - return (error); +static inline int +pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val) +{ + return (pcie_capability_clear_and_set_word(dev, pos, val, 0)); } static inline int pcie_get_minimum_link(struct pci_dev *dev, @@ -1534,97 +1330,10 @@ /* -------------------------------------------------------------------------- */ -static inline int -pcim_enable_device(struct pci_dev *pdev) -{ - struct pci_devres *dr; - int error; - - /* Here we cannot run through the pdev->managed check. */ - dr = lkpi_pci_devres_get_alloc(pdev); - if (dr == NULL) - return (-ENOMEM); - - /* If resources were enabled before do not do it again. */ - if (dr->enable_io) - return (0); - - error = pci_enable_device(pdev); - if (error == 0) - dr->enable_io = true; - - /* This device is not managed. */ - pdev->managed = true; - - return (error); -} - -static inline void __iomem ** -pcim_iomap_table(struct pci_dev *pdev) -{ - struct pcim_iomap_devres *dr; - - dr = lkpi_pcim_iomap_devres_find(pdev); - if (dr == NULL) - return (NULL); - - /* - * If the driver has manually set a flag to be able to request the - * resource to use bus_read/write_, return the shadow table. - */ - if (pdev->want_iomap_res) - return ((void **)dr->res_table); - - /* This is the Linux default. */ - return (dr->mmio_table); -} - -static inline int -pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *name) -{ - struct pcim_iomap_devres *dr; - void *res; - uint32_t mappings; - int bar; - - dr = lkpi_pcim_iomap_devres_find(pdev); - if (dr == NULL) - return (-ENOMEM); - - /* Now iomap all the requested (by "mask") ones. */ - for (bar = mappings = 0; mappings != mask; bar++) { - if ((mask & (1 << bar)) == 0) - continue; - - /* Request double is not allowed. */ - if (dr->mmio_table[bar] != NULL) { - device_printf(pdev->dev.bsddev, "%s: bar %d %p\n", - __func__, bar, dr->mmio_table[bar]); - goto err; - } - - res = _lkpi_pci_iomap(pdev, bar, 0); - if (res == NULL) - goto err; - dr->mmio_table[bar] = (void *)rman_get_bushandle(res); - dr->res_table[bar] = res; - - mappings |= (1 << bar); - } - - return (0); -err: - for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) { - if ((mappings & (1 << bar)) != 0) { - res = dr->mmio_table[bar]; - if (res == NULL) - continue; - pci_iounmap(pdev, res); - } - } - - return (-EINVAL); -} +#define pcim_enable_device(pdev) linuxkpi_pcim_enable_device(pdev) +#define pcim_iomap_table(pdev) linuxkpi_pcim_iomap_table(pdev) +#define pcim_iomap_regions(pdev, mask, name) \ + linuxkpi_pcim_iomap_regions(pdev, mask, name) static inline int pcim_iomap_regions_request_all(struct pci_dev *pdev, uint32_t mask, char *name) diff --git a/sys/compat/linuxkpi/common/include/linux/random.h b/sys/compat/linuxkpi/common/include/linux/random.h --- a/sys/compat/linuxkpi/common/include/linux/random.h +++ b/sys/compat/linuxkpi/common/include/linux/random.h @@ -87,6 +87,15 @@ return (val); } +static inline uint64_t +get_random_u64(void) +{ + uint64_t val; + + get_random_bytes(&val, sizeof(val)); + return (val); +} + static __inline uint32_t prandom_u32(void) { diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h --- a/sys/compat/linuxkpi/common/include/linux/sched.h +++ b/sys/compat/linuxkpi/common/include/linux/sched.h @@ -64,6 +64,7 @@ #define TASK_COMM_LEN (MAXCOMLEN + 1) struct seq_file; +struct fpu_kern_ctx; struct work_struct; struct task_struct { @@ -89,6 +90,7 @@ struct task_struct *group_leader; unsigned rcu_section[TS_RCU_TYPE_MAX]; unsigned int fpu_ctx_level; + struct fpu_kern_ctx *fpu_ctx; }; #define current ({ \ diff --git a/sys/compat/linuxkpi/common/include/linux/seqlock.h b/sys/compat/linuxkpi/common/include/linux/seqlock.h --- a/sys/compat/linuxkpi/common/include/linux/seqlock.h +++ b/sys/compat/linuxkpi/common/include/linux/seqlock.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -84,9 +85,24 @@ struct seqcount_mutex: seqc_write_end \ )(&(s)->seqc) +static inline void +lkpi_write_seqcount_invalidate(seqc_t *seqcp) +{ + atomic_thread_fence_rel(); + *seqcp += SEQC_MOD * 2; +} +#define write_seqcount_invalidate(s) lkpi_write_seqcount_invalidate(&(s)->seqc) + #define read_seqcount_begin(s) seqc_read(&(s)->seqc) #define raw_read_seqcount(s) seqc_read_any(&(s)->seqc) +static inline seqc_t +lkpi_seqprop_sequence(const seqc_t *seqcp) +{ + return (atomic_load_int(__DECONST(seqc_t *, seqcp))); +} +#define seqprop_sequence(s) lkpi_seqprop_sequence(&(s)->seqc) + /* * XXX: Are predicts from inline functions still not honored by clang? */ diff --git a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h --- a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h +++ b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h @@ -29,7 +29,10 @@ #ifndef _LINUXKPI_LINUX_SHMEM_FS_H_ #define _LINUXKPI_LINUX_SHMEM_FS_H_ +#include +#include #include +#include /* Shared memory support */ struct page *linux_shmem_read_mapping_page_gfp(vm_object_t obj, int pindex, diff --git a/sys/compat/linuxkpi/common/include/linux/shrinker.h b/sys/compat/linuxkpi/common/include/linux/shrinker.h --- a/sys/compat/linuxkpi/common/include/linux/shrinker.h +++ b/sys/compat/linuxkpi/common/include/linux/shrinker.h @@ -51,7 +51,11 @@ void linuxkpi_unregister_shrinker(struct shrinker *s); void linuxkpi_synchronize_shrinkers(void); +#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60000 +#define register_shrinker(s, ...) linuxkpi_register_shrinker(s) +#else #define register_shrinker(s) linuxkpi_register_shrinker(s) +#endif #define unregister_shrinker(s) linuxkpi_unregister_shrinker(s) #define synchronize_shrinkers() linuxkpi_synchronize_shrinkers() diff --git a/sys/compat/linuxkpi/common/include/linux/string_helpers.h b/sys/compat/linuxkpi/common/include/linux/string_helpers.h --- a/sys/compat/linuxkpi/common/include/linux/string_helpers.h +++ b/sys/compat/linuxkpi/common/include/linux/string_helpers.h @@ -39,4 +39,31 @@ return "no"; } -#endif /* _LINUXKPI_LINUX_STRING_HELPERS_H_ */ +static inline const char * +str_on_off(bool value) +{ + if (value) + return "on"; + else + return "off"; +} + +static inline const char * +str_enabled_disabled(bool value) +{ + if (value) + return "enabled"; + else + return "disabled"; +} + +static inline const char * +str_enable_disable(bool value) +{ + if (value) + return "enable"; + else + return "disable"; +} + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h --- a/sys/compat/linuxkpi/common/include/linux/workqueue.h +++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h @@ -188,6 +188,9 @@ #define delayed_work_pending(dwork) \ linux_work_pending(&(dwork)->work) +#define cancel_work(work) \ + linux_cancel_work(work) + #define cancel_delayed_work(dwork) \ linux_cancel_delayed_work(dwork) @@ -243,6 +246,7 @@ extern bool linux_queue_work_on(int cpu, struct workqueue_struct *, struct work_struct *); extern bool linux_queue_delayed_work_on(int cpu, struct workqueue_struct *, struct delayed_work *, unsigned delay); +extern bool linux_cancel_work(struct work_struct *); extern bool linux_cancel_delayed_work(struct delayed_work *); extern bool linux_cancel_work_sync(struct work_struct *); extern bool linux_cancel_delayed_work_sync(struct delayed_work *); diff --git a/sys/compat/linuxkpi/common/include/linux/xarray.h b/sys/compat/linuxkpi/common/include/linux/xarray.h --- a/sys/compat/linuxkpi/common/include/linux/xarray.h +++ b/sys/compat/linuxkpi/common/include/linux/xarray.h @@ -95,6 +95,9 @@ #define xa_erase_irq(xa, index) \ xa_erase((xa), (index)) +#define xa_lock_irq(xa) xa_lock(xa) +#define xa_unlock_irq(xa) xa_unlock(xa) + #define xa_lock_irqsave(xa, flags) \ do { \ xa_lock((xa)); \ diff --git a/sys/compat/linuxkpi/common/include/video/vga.h b/sys/compat/linuxkpi/common/include/video/vga.h new file mode 100644 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/video/vga.h @@ -0,0 +1,16 @@ +/* Public domain. */ + +#ifndef _LINUXKPI_VIDEO_VGA_H +#define _LINUXKPI_VIDEO_VGA_H + +#define VGA_MIS_W 0x3c2 +#define VGA_SEQ_I 0x3c4 +#define VGA_SEQ_D 0x3c5 +#define VGA_MIS_R 0x3cc + +#define VGA_SR01_SCREEN_OFF (1 << 5) + +#define VGA_FB_PHYS_BASE 0xA0000 +#define VGA_FB_PHYS_SIZE 65536 + +#endif diff --git a/sys/compat/linuxkpi/common/include/acpi/video.h b/sys/compat/linuxkpi/common/include/xen/xen.h copy from sys/compat/linuxkpi/common/include/acpi/video.h copy to sys/compat/linuxkpi/common/include/xen/xen.h --- a/sys/compat/linuxkpi/common/include/acpi/video.h +++ b/sys/compat/linuxkpi/common/include/xen/xen.h @@ -1,17 +1,16 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2020 Vladimir Kondratyev + * Copyright (c) 2023 Serenity Cyber Security, LLC. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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. + * 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 @@ -26,25 +25,13 @@ * SUCH DAMAGE. */ -#ifndef _LINUXKPI_ACPI_VIDEO_H_ -#define _LINUXKPI_ACPI_VIDEO_H_ +#ifndef _LINUXKPI_XEN_XEN_H_ +#define _LINUXKPI_XEN_XEN_H_ -#include +#define xen_initial_domain() lkpi_xen_initial_domain() +#define xen_pv_domain() lkpi_xen_pv_domain() -#define ACPI_VIDEO_CLASS "video" +bool lkpi_xen_initial_domain(void); +bool lkpi_xen_pv_domain(void); -#define ACPI_VIDEO_NOTIFY_PROBE 0x81 - -static inline int -acpi_video_register(void) -{ - - return (-ENODEV); -} - -static inline void -acpi_video_unregister(void) -{ -} - -#endif /* _LINUXKPI_ACPI_VIDEO_H_ */ +#endif /* _LINUXKPI_XEN_XEN_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_acpi.c b/sys/compat/linuxkpi/common/src/linux_acpi.c --- a/sys/compat/linuxkpi/common/src/linux_acpi.c +++ b/sys/compat/linuxkpi/common/src/linux_acpi.c @@ -174,6 +174,79 @@ return (linux_acpi_target_sleep_state); } +struct acpi_dev_present_ctx { + const char *hid; + const char *uid; + int64_t hrv; +}; + +static ACPI_STATUS +acpi_dev_present_cb(ACPI_HANDLE handle, UINT32 level, void *context, + void **result) +{ + ACPI_DEVICE_INFO *devinfo; + struct acpi_dev_present_ctx *match = context; + bool present = false; + UINT32 sta, hrv; + int i; + + if (handle == NULL) + return (AE_OK); + + if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) && + !ACPI_DEVICE_PRESENT(sta)) + return (AE_OK); + + if (ACPI_FAILURE(AcpiGetObjectInfo(handle, &devinfo))) + return (AE_OK); + + if ((devinfo->Valid & ACPI_VALID_HID) != 0 && + strcmp(match->hid, devinfo->HardwareId.String) == 0) { + present = true; + } else if ((devinfo->Valid & ACPI_VALID_CID) != 0) { + for (i = 0; i < devinfo->CompatibleIdList.Count; i++) { + if (strcmp(match->hid, + devinfo->CompatibleIdList.Ids[i].String) == 0) { + present = true; + break; + } + } + } + if (present && match->uid != NULL && + ((devinfo->Valid & ACPI_VALID_UID) == 0 || + strcmp(match->uid, devinfo->UniqueId.String) != 0)) + present = false; + + AcpiOsFree(devinfo); + if (!present) + return (AE_OK); + + if (match->hrv != -1) { + if (ACPI_FAILURE(acpi_GetInteger(handle, "_HRV", &hrv))) + return (AE_OK); + if (hrv != match->hrv) + return (AE_OK); + } + + return (AE_ERROR); +} + +bool +lkpi_acpi_dev_present(const char *hid, const char *uid, int64_t hrv) +{ + struct acpi_dev_present_ctx match; + int rv; + + match.hid = hid; + match.uid = uid; + match.hrv = hrv; + + rv = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, acpi_dev_present_cb, NULL, &match, NULL); + + return (rv == AE_ERROR); +} + static void linux_register_acpi_event_handlers(void *arg __unused) { @@ -241,4 +314,10 @@ return (ACPI_STATE_S0); } +bool +lkpi_acpi_dev_present(const char *hid, const char *uid, int64_t hrv) +{ + return (false); +} + #endif /* !DEV_ACPI */ diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -28,6 +28,7 @@ */ #include +#include "opt_global.h" #include "opt_stack.h" #include @@ -62,6 +63,7 @@ #include #if defined(__i386__) || defined(__amd64__) +#include #include #endif @@ -99,6 +101,15 @@ #include #endif +#include +#ifdef XENHVM +#undef xen_pv_domain +#undef xen_initial_domain +/* xen/xen-os.h redefines __must_check */ +#undef __must_check +#include +#endif + SYSCTL_NODE(_compat, OID_AUTO, linuxkpi, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "LinuxKPI parameters"); @@ -131,7 +142,8 @@ static struct vm_area_struct *linux_cdev_handle_find(void *handle); cpumask_t cpu_online_mask; -static cpumask_t static_single_cpu_mask[MAXCPU]; +static cpumask_t **static_single_cpu_mask; +static cpumask_t *static_single_cpu_mask_lcs; struct kobject linux_class_root; struct device linux_root_device; struct class linux_class_misc; @@ -2569,17 +2581,39 @@ #if defined(__i386__) || defined(__amd64__) bool linux_cpu_has_clflush; struct cpuinfo_x86 boot_cpu_data; -struct cpuinfo_x86 __cpu_data[MAXCPU]; +struct cpuinfo_x86 *__cpu_data; #endif cpumask_t * lkpi_get_static_single_cpu_mask(int cpuid) { - KASSERT((cpuid >= 0 && cpuid < MAXCPU), ("%s: invalid cpuid %d\n", + KASSERT((cpuid >= 0 && cpuid <= mp_maxid), ("%s: invalid cpuid %d\n", + __func__, cpuid)); + KASSERT(!CPU_ABSENT(cpuid), ("%s: cpu with cpuid %d is absent\n", __func__, cpuid)); - return (&static_single_cpu_mask[cpuid]); + return (static_single_cpu_mask[cpuid]); +} + +bool +lkpi_xen_initial_domain(void) +{ +#ifdef XENHVM + return (xen_initial_domain()); +#else + return (false); +#endif +} + +bool +lkpi_xen_pv_domain(void) +{ +#ifdef XENHVM + return (xen_pv_domain()); +#else + return (false); +#endif } static void @@ -2589,17 +2623,39 @@ int i; #if defined(__i386__) || defined(__amd64__) + static const uint32_t x86_vendors[X86_VENDOR_NUM] = { + [X86_VENDOR_INTEL] = CPU_VENDOR_INTEL, + [X86_VENDOR_CYRIX] = CPU_VENDOR_CYRIX, + [X86_VENDOR_AMD] = CPU_VENDOR_AMD, + [X86_VENDOR_UMC] = CPU_VENDOR_UMC, + [X86_VENDOR_CENTAUR] = CPU_VENDOR_CENTAUR, + [X86_VENDOR_TRANSMETA] = CPU_VENDOR_TRANSMETA, + [X86_VENDOR_NSC] = CPU_VENDOR_NSC, + [X86_VENDOR_HYGON] = CPU_VENDOR_HYGON, + }; + uint8_t x86_vendor = X86_VENDOR_UNKNOWN; + + for (i = 0; i < X86_VENDOR_NUM; i++) { + if (cpu_vendor_id != 0 && cpu_vendor_id == x86_vendors[i]) { + x86_vendor = i; + break; + } + } linux_cpu_has_clflush = (cpu_feature & CPUID_CLFSH); boot_cpu_data.x86_clflush_size = cpu_clflush_line_size; boot_cpu_data.x86_max_cores = mp_ncpus; boot_cpu_data.x86 = CPUID_TO_FAMILY(cpu_id); boot_cpu_data.x86_model = CPUID_TO_MODEL(cpu_id); + boot_cpu_data.x86_vendor = x86_vendor; - for (i = 0; i < MAXCPU; i++) { + __cpu_data = mallocarray(mp_maxid + 1, + sizeof(*__cpu_data), M_KMALLOC, M_WAITOK | M_ZERO); + CPU_FOREACH(i) { __cpu_data[i].x86_clflush_size = cpu_clflush_line_size; __cpu_data[i].x86_max_cores = mp_ncpus; __cpu_data[i].x86 = CPUID_TO_FAMILY(cpu_id); __cpu_data[i].x86_model = CPUID_TO_MODEL(cpu_id); + __cpu_data[i].x86_vendor = x86_vendor; } #endif rw_init(&linux_vma_lock, "lkpi-vma-lock"); @@ -2630,13 +2686,92 @@ CPU_COPY(&all_cpus, &cpu_online_mask); /* * Generate a single-CPU cpumask_t for each CPU (possibly) in the system. - * CPUs are indexed from 0..(MAXCPU-1). The entry for cpuid 0 will only + * CPUs are indexed from 0..(mp_maxid). The entry for cpuid 0 will only * have itself in the cpumask, cupid 1 only itself on entry 1, and so on. * This is used by cpumask_of() (and possibly others in the future) for, * e.g., drivers to pass hints to irq_set_affinity_hint(). */ - for (i = 0; i < MAXCPU; i++) - CPU_SET(i, &static_single_cpu_mask[i]); + static_single_cpu_mask = mallocarray(mp_maxid + 1, + sizeof(static_single_cpu_mask), M_KMALLOC, M_WAITOK | M_ZERO); + + /* + * When the number of CPUs reach a threshold, we start to save memory + * given the sets are static by overlapping those having their single + * bit set at same position in a bitset word. Asymptotically, this + * regular scheme is in O(n²) whereas the overlapping one is in O(n) + * only with n being the maximum number of CPUs, so the gain will become + * huge quite quickly. The threshold for 64-bit architectures is 128 + * CPUs. + */ + if (mp_ncpus < (2 * _BITSET_BITS)) { + cpumask_t *sscm_ptr; + + /* + * This represents 'mp_ncpus * __bitset_words(CPU_SETSIZE) * + * (_BITSET_BITS / 8)' bytes (for comparison with the + * overlapping scheme). + */ + static_single_cpu_mask_lcs = mallocarray(mp_ncpus, + sizeof(*static_single_cpu_mask_lcs), + M_KMALLOC, M_WAITOK | M_ZERO); + + sscm_ptr = static_single_cpu_mask_lcs; + CPU_FOREACH(i) { + static_single_cpu_mask[i] = sscm_ptr++; + CPU_SET(i, static_single_cpu_mask[i]); + } + } else { + /* Pointer to a bitset word. */ + __typeof(((cpuset_t *)NULL)->__bits[0]) *bwp; + + /* + * Allocate memory for (static) spans of 'cpumask_t' ('cpuset_t' + * really) with a single bit set that can be reused for all + * single CPU masks by making them start at different offsets. + * We need '__bitset_words(CPU_SETSIZE) - 1' bitset words before + * the word having its single bit set, and the same amount + * after. + */ + static_single_cpu_mask_lcs = mallocarray(_BITSET_BITS, + (2 * __bitset_words(CPU_SETSIZE) - 1) * (_BITSET_BITS / 8), + M_KMALLOC, M_WAITOK | M_ZERO); + + /* + * We rely below on cpuset_t and the bitset generic + * implementation assigning words in the '__bits' array in the + * same order of bits (i.e., little-endian ordering, not to be + * confused with machine endianness, which concerns bits in + * words and other integers). This is an imperfect test, but it + * will detect a change to big-endian ordering. + */ + _Static_assert( + __bitset_word(_BITSET_BITS + 1, _BITSET_BITS) == 1, + "Assumes a bitset implementation that is little-endian " + "on its words"); + + /* Initialize the single bit of each static span. */ + bwp = (__typeof(bwp))static_single_cpu_mask_lcs + + (__bitset_words(CPU_SETSIZE) - 1); + for (i = 0; i < _BITSET_BITS; i++) { + CPU_SET(i, (cpuset_t *)bwp); + bwp += (2 * __bitset_words(CPU_SETSIZE) - 1); + } + + /* + * Finally set all CPU masks to the proper word in their + * relevant span. + */ + CPU_FOREACH(i) { + bwp = (__typeof(bwp))static_single_cpu_mask_lcs; + /* Find the non-zero word of the relevant span. */ + bwp += (2 * __bitset_words(CPU_SETSIZE) - 1) * + (i % _BITSET_BITS) + + __bitset_words(CPU_SETSIZE) - 1; + /* Shift to find the CPU mask start. */ + bwp -= (i / _BITSET_BITS); + static_single_cpu_mask[i] = (cpuset_t *)bwp; + } + } strlcpy(init_uts_ns.name.release, osrelease, sizeof(init_uts_ns.name.release)); } @@ -2649,6 +2784,12 @@ linux_kobject_kfree_name(&linux_root_device.kobj); linux_kobject_kfree_name(&linux_class_misc.kobj); + free(static_single_cpu_mask_lcs, M_KMALLOC); + free(static_single_cpu_mask, M_KMALLOC); +#if defined(__i386__) || defined(__amd64__) + free(__cpu_data, M_KMALLOC); +#endif + mtx_destroy(&vmmaplock); spin_lock_destroy(&pci_lock); rw_destroy(&linux_vma_lock); diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c --- a/sys/compat/linuxkpi/common/src/linux_current.c +++ b/sys/compat/linuxkpi/common/src/linux_current.c @@ -43,6 +43,11 @@ #include #include +#if defined(__aarch64__) || defined(__arm__) || defined(__amd64__) || \ + defined(__i386__) +#include +#endif + #ifdef DEV_APIC extern u_int first_msi_irq, num_msi_irqs; #endif @@ -153,6 +158,17 @@ return (0); } +int +linux_set_fpu_ctx(struct task_struct *task) +{ +#if defined(__aarch64__) || defined(__arm__) || defined(__amd64__) || \ + defined(__i386__) + if (task->fpu_ctx == NULL && curthread->td_critnest == 0) + task->fpu_ctx = fpu_kern_alloc_ctx(FPU_KERN_NOWAIT); +#endif + return (task->fpu_ctx != NULL ? 0 : ENOMEM); +} + struct mm_struct * linux_get_task_mm(struct task_struct *task) { @@ -176,6 +192,11 @@ linux_free_current(struct task_struct *ts) { mmput(ts->mm); +#if defined(__aarch64__) || defined(__arm__) || defined(__amd64__) || \ + defined(__i386__) + if (ts->fpu_ctx != NULL) + fpu_kern_free_ctx(ts->fpu_ctx); +#endif uma_zfree(linux_current_zone, ts); } diff --git a/sys/compat/linuxkpi/common/src/linux_fpu.c b/sys/compat/linuxkpi/common/src/linux_fpu.c --- a/sys/compat/linuxkpi/common/src/linux_fpu.c +++ b/sys/compat/linuxkpi/common/src/linux_fpu.c @@ -30,11 +30,13 @@ #include #include +#include #include #include -#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__) +#if defined(__aarch64__) || defined(__arm__) || defined(__amd64__) || \ + defined(__i386__) || defined(__powerpc64__) #include @@ -47,15 +49,20 @@ void lkpi_kernel_fpu_begin(void) { - if ((current->fpu_ctx_level)++ == 0) - fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + int err; + + if ((current->fpu_ctx_level)++ == 0) { + err = linux_set_fpu_ctx(current); + fpu_kern_enter(curthread, current->fpu_ctx, + err == 0 ? FPU_KERN_KTHR : FPU_KERN_NOCTX); + } } void lkpi_kernel_fpu_end(void) { if (--(current->fpu_ctx_level) == 0) - fpu_kern_leave(curthread, NULL); + fpu_kern_leave(curthread, current->fpu_ctx); } #else diff --git a/sys/compat/linuxkpi/common/src/linux_idr.c b/sys/compat/linuxkpi/common/src/linux_idr.c --- a/sys/compat/linuxkpi/common/src/linux_idr.c +++ b/sys/compat/linuxkpi/common/src/linux_idr.c @@ -754,10 +754,9 @@ unsigned int max; MPASS((int)start >= 0); - MPASS((int)end >= 0); - if (end == 0) - max = 0x80000000; + if ((int)end <= 0) + max = INT_MAX; else { MPASS(end > start); max = end - 1; diff --git a/sys/compat/linuxkpi/common/src/linux_interrupt.c b/sys/compat/linuxkpi/common/src/linux_interrupt.c --- a/sys/compat/linuxkpi/common/src/linux_interrupt.c +++ b/sys/compat/linuxkpi/common/src/linux_interrupt.c @@ -117,17 +117,20 @@ struct resource *res; struct irq_ent *irqe; struct device *dev; + unsigned resflags; int error; int rid; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return -ENXIO; if (xdev != NULL && xdev != dev) return -ENXIO; rid = lkpi_irq_rid(dev, irq); - res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, - flags | RF_ACTIVE); + resflags = RF_ACTIVE; + if ((flags & IRQF_SHARED) != 0) + resflags |= RF_SHAREABLE; + res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, resflags); if (res == NULL) return (-ENXIO); if (xdev != NULL) @@ -167,7 +170,7 @@ struct irq_ent *irqe; struct device *dev; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return -EINVAL; irqe = lkpi_irq_ent(dev, irq); @@ -183,7 +186,7 @@ struct irq_ent *irqe; struct device *dev; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return; irqe = lkpi_irq_ent(dev, irq); @@ -200,7 +203,7 @@ struct irq_ent *irqe; struct device *dev; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return (-ENOENT); @@ -217,7 +220,7 @@ struct irq_ent *irqe; struct device *dev; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return; irqe = lkpi_irq_ent(dev, irq); @@ -233,7 +236,7 @@ struct device *dev; struct irq_ent *irqe; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return; if (xdev != dev) diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c --- a/sys/compat/linuxkpi/common/src/linux_page.c +++ b/sys/compat/linuxkpi/common/src/linux_page.c @@ -118,10 +118,12 @@ PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); if (page == NULL) { if (flags & M_WAITOK) { - if (!vm_page_reclaim_contig(req, - npages, 0, pmax, PAGE_SIZE, 0)) { + int err = vm_page_reclaim_contig(req, + npages, 0, pmax, PAGE_SIZE, 0); + if (err == ENOMEM) vm_wait(NULL); - } + else if (err != 0) + return (NULL); flags &= ~M_WAITOK; goto retry; } diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -41,11 +41,14 @@ #include #include #include +#include #include #include #include +#include +#include #include #include @@ -95,6 +98,7 @@ static int linux_backlight_get_status(device_t dev, struct backlight_props *props); static int linux_backlight_update_status(device_t dev, struct backlight_props *props); static int linux_backlight_get_info(device_t dev, struct backlight_info *info); +static void lkpi_pcim_iomap_table_release(struct device *, void *); static device_method_t pci_methods[] = { DEVMETHOD(device_probe, linux_pci_probe), @@ -118,6 +122,18 @@ "UNKNOWN", "D0", "D1", "D2", "D3hot", "D3cold" }; +/* We need some meta-struct to keep track of these for devres. */ +struct pci_devres { + bool enable_io; + /* PCIR_MAX_BAR_0 + 1 = 6 => BIT(0..5). */ + uint8_t region_mask; + struct resource *region_table[PCIR_MAX_BAR_0 + 1]; /* Not needed. */ +}; +struct pcim_iomap_devres { + void *mmio_table[PCIR_MAX_BAR_0 + 1]; + struct resource *res_table[PCIR_MAX_BAR_0 + 1]; +}; + struct linux_dma_priv { uint64_t dma_mask; bus_dma_tag_t dmat; @@ -434,6 +450,41 @@ return (linux_pci_attach_device(dev, pdrv, id, pdev)); } +static struct resource_list_entry * +linux_pci_reserve_bar(struct pci_dev *pdev, struct resource_list *rl, + int type, int rid) +{ + device_t dev; + struct resource *res; + + KASSERT(type == SYS_RES_IOPORT || type == SYS_RES_MEMORY, + ("trying to reserve non-BAR type %d", type)); + + dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ? + device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev; + res = pci_reserve_map(device_get_parent(dev), dev, type, &rid, 0, ~0, + 1, 1, 0); + if (res == NULL) + return (NULL); + return (resource_list_find(rl, type, rid)); +} + +static struct resource_list_entry * +linux_pci_get_rle(struct pci_dev *pdev, int type, int rid, bool reserve_bar) +{ + struct pci_devinfo *dinfo; + struct resource_list *rl; + struct resource_list_entry *rle; + + dinfo = device_get_ivars(pdev->dev.bsddev); + rl = &dinfo->resources; + rle = resource_list_find(rl, type, rid); + /* Reserve resources for this BAR if needed. */ + if (rle == NULL && reserve_bar) + rle = linux_pci_reserve_bar(pdev, rl, type, rid); + return (rle); +} + int linux_pci_attach_device(device_t dev, struct pci_driver *pdrv, const struct pci_device_id *id, struct pci_dev *pdev) @@ -474,6 +525,7 @@ goto out_dma_init; TAILQ_INIT(&pdev->mmio); + spin_lock_init(&pdev->pcie_cap_lock); spin_lock(&pci_lock); list_add(&pdev->links, &pci_devices); @@ -488,6 +540,7 @@ out_probe: free(pdev->bus, M_DEVBUF); + spin_lock_destroy(&pdev->pcie_cap_lock); linux_pdev_dma_uninit(pdev); out_dma_init: spin_lock(&pci_lock); @@ -528,6 +581,7 @@ spin_lock(&pci_lock); list_del(&pdev->links); spin_unlock(&pci_lock); + spin_lock_destroy(&pdev->pcie_cap_lock); put_device(&pdev->dev); return (0); @@ -542,7 +596,7 @@ return (0); } -struct pci_devres * +static struct pci_devres * lkpi_pci_devres_get_alloc(struct pci_dev *pdev) { struct pci_devres *dr; @@ -558,6 +612,15 @@ return (dr); } +static struct pci_devres * +lkpi_pci_devres_find(struct pci_dev *pdev) +{ + if (!pdev->managed) + return (NULL); + + return (lkpi_pci_devres_get_alloc(pdev)); +} + void lkpi_pci_devres_release(struct device *dev, void *p) { @@ -586,7 +649,32 @@ } } -struct pcim_iomap_devres * +int +linuxkpi_pcim_enable_device(struct pci_dev *pdev) +{ + struct pci_devres *dr; + int error; + + /* Here we cannot run through the pdev->managed check. */ + dr = lkpi_pci_devres_get_alloc(pdev); + if (dr == NULL) + return (-ENOMEM); + + /* If resources were enabled before do not do it again. */ + if (dr->enable_io) + return (0); + + error = pci_enable_device(pdev); + if (error == 0) + dr->enable_io = true; + + /* This device is not managed. */ + pdev->managed = true; + + return (error); +} + +static struct pcim_iomap_devres * lkpi_pcim_iomap_devres_find(struct pci_dev *pdev) { struct pcim_iomap_devres *dr; @@ -606,7 +694,144 @@ return (dr); } +void __iomem ** +linuxkpi_pcim_iomap_table(struct pci_dev *pdev) +{ + struct pcim_iomap_devres *dr; + + dr = lkpi_pcim_iomap_devres_find(pdev); + if (dr == NULL) + return (NULL); + + /* + * If the driver has manually set a flag to be able to request the + * resource to use bus_read/write_, return the shadow table. + */ + if (pdev->want_iomap_res) + return ((void **)dr->res_table); + + /* This is the Linux default. */ + return (dr->mmio_table); +} + +static struct resource * +_lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size __unused) +{ + struct pci_mmio_region *mmio, *p; + int type; + + type = pci_resource_type(pdev, bar); + if (type < 0) { + device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n", + __func__, bar, type); + return (NULL); + } + + /* + * Check for duplicate mappings. + * This can happen if a driver calls pci_request_region() first. + */ + TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { + if (mmio->type == type && mmio->rid == PCIR_BAR(bar)) { + return (mmio->res); + } + } + + mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO); + mmio->rid = PCIR_BAR(bar); + mmio->type = type; + mmio->res = bus_alloc_resource_any(pdev->dev.bsddev, mmio->type, + &mmio->rid, RF_ACTIVE|RF_SHAREABLE); + if (mmio->res == NULL) { + device_printf(pdev->dev.bsddev, "%s: failed to alloc " + "bar %d type %d rid %d\n", + __func__, bar, type, PCIR_BAR(bar)); + free(mmio, M_DEVBUF); + return (NULL); + } + TAILQ_INSERT_TAIL(&pdev->mmio, mmio, next); + + return (mmio->res); +} + +void * +linuxkpi_pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size) +{ + struct resource *res; + + res = _lkpi_pci_iomap(pdev, mmio_bar, mmio_size); + if (res == NULL) + return (NULL); + /* This is a FreeBSD extension so we can use bus_*(). */ + if (pdev->want_iomap_res) + return (res); + return ((void *)rman_get_bushandle(res)); +} + void +linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res) +{ + struct pci_mmio_region *mmio, *p; + + TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { + if (res != (void *)rman_get_bushandle(mmio->res)) + continue; + bus_release_resource(pdev->dev.bsddev, + mmio->type, mmio->rid, mmio->res); + TAILQ_REMOVE(&pdev->mmio, mmio, next); + free(mmio, M_DEVBUF); + return; + } +} + +int +linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *name) +{ + struct pcim_iomap_devres *dr; + void *res; + uint32_t mappings; + int bar; + + dr = lkpi_pcim_iomap_devres_find(pdev); + if (dr == NULL) + return (-ENOMEM); + + /* Now iomap all the requested (by "mask") ones. */ + for (bar = mappings = 0; mappings != mask; bar++) { + if ((mask & (1 << bar)) == 0) + continue; + + /* Request double is not allowed. */ + if (dr->mmio_table[bar] != NULL) { + device_printf(pdev->dev.bsddev, "%s: bar %d %p\n", + __func__, bar, dr->mmio_table[bar]); + goto err; + } + + res = _lkpi_pci_iomap(pdev, bar, 0); + if (res == NULL) + goto err; + dr->mmio_table[bar] = (void *)rman_get_bushandle(res); + dr->res_table[bar] = res; + + mappings |= (1 << bar); + } + + return (0); +err: + for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) { + if ((mappings & (1 << bar)) != 0) { + res = dr->mmio_table[bar]; + if (res == NULL) + continue; + pci_iounmap(pdev, res); + } + } + + return (-EINVAL); +} + +static void lkpi_pcim_iomap_table_release(struct device *dev, void *p) { struct pcim_iomap_devres *dr; @@ -758,23 +983,35 @@ return (_linux_pci_register_driver(pdrv, dc)); } -struct resource_list_entry * -linux_pci_reserve_bar(struct pci_dev *pdev, struct resource_list *rl, - int type, int rid) +static struct resource_list_entry * +lkpi_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve) { - device_t dev; - struct resource *res; - - KASSERT(type == SYS_RES_IOPORT || type == SYS_RES_MEMORY, - ("trying to reserve non-BAR type %d", type)); + int type; - dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ? - device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev; - res = pci_reserve_map(device_get_parent(dev), dev, type, &rid, 0, ~0, - 1, 1, 0); - if (res == NULL) + type = pci_resource_type(pdev, bar); + if (type < 0) return (NULL); - return (resource_list_find(rl, type, rid)); + bar = PCIR_BAR(bar); + return (linux_pci_get_rle(pdev, type, bar, reserve)); +} + +struct device * +lkpi_pci_find_irq_dev(unsigned int irq) +{ + struct pci_dev *pdev; + struct device *found; + + found = NULL; + spin_lock(&pci_lock); + list_for_each_entry(pdev, &pci_devices, links) { + if (irq == pdev->dev.irq || + (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) { + found = &pdev->dev; + break; + } + } + spin_unlock(&pci_lock); + return (found); } unsigned long @@ -785,7 +1022,7 @@ device_t dev; int error; - if ((rle = linux_pci_get_bar(pdev, bar, true)) == NULL) + if ((rle = lkpi_pci_get_bar(pdev, bar, true)) == NULL) return (0); dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ? device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev; @@ -804,7 +1041,7 @@ { struct resource_list_entry *rle; - if ((rle = linux_pci_get_bar(pdev, bar, true)) == NULL) + if ((rle = lkpi_pci_get_bar(pdev, bar, true)) == NULL) return (0); return (rle->count); } @@ -853,44 +1090,62 @@ return (0); } -struct resource * -_lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size __unused) +int +linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name) { - struct pci_mmio_region *mmio, *p; - int type; + int error; + int i; - type = pci_resource_type(pdev, bar); - if (type < 0) { - device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n", - __func__, bar, type); - return (NULL); + for (i = 0; i <= PCIR_MAX_BAR_0; i++) { + error = pci_request_region(pdev, i, res_name); + if (error && error != -ENODEV) { + pci_release_regions(pdev); + return (error); + } } + return (0); +} + +void +linuxkpi_pci_release_region(struct pci_dev *pdev, int bar) +{ + struct resource_list_entry *rle; + struct pci_devres *dr; + struct pci_mmio_region *mmio, *p; + + if ((rle = lkpi_pci_get_bar(pdev, bar, false)) == NULL) + return; /* - * Check for duplicate mappings. - * This can happen if a driver calls pci_request_region() first. + * As we implicitly track the requests we also need to clear them on + * release. Do clear before resource release. */ - TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { - if (mmio->type == type && mmio->rid == PCIR_BAR(bar)) { - return (mmio->res); - } + dr = lkpi_pci_devres_find(pdev); + if (dr != NULL) { + KASSERT(dr->region_table[bar] == rle->res, ("%s: pdev %p bar %d" + " region_table res %p != rel->res %p\n", __func__, pdev, + bar, dr->region_table[bar], rle->res)); + dr->region_table[bar] = NULL; + dr->region_mask &= ~(1 << bar); } - mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO); - mmio->rid = PCIR_BAR(bar); - mmio->type = type; - mmio->res = bus_alloc_resource_any(pdev->dev.bsddev, mmio->type, - &mmio->rid, RF_ACTIVE|RF_SHAREABLE); - if (mmio->res == NULL) { - device_printf(pdev->dev.bsddev, "%s: failed to alloc " - "bar %d type %d rid %d\n", - __func__, bar, type, PCIR_BAR(bar)); + TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) { + if (rle->res != (void *)rman_get_bushandle(mmio->res)) + continue; + TAILQ_REMOVE(&pdev->mmio, mmio, next); free(mmio, M_DEVBUF); - return (NULL); } - TAILQ_INSERT_TAIL(&pdev->mmio, mmio, next); - return (mmio->res); + bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res); +} + +void +linuxkpi_pci_release_regions(struct pci_dev *pdev) +{ + int i; + + for (i = 0; i <= PCIR_MAX_BAR_0; i++) + pci_release_region(pdev, i); } int @@ -938,6 +1193,73 @@ bus_topo_unlock(); } +int +linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, + int nreq) +{ + struct resource_list_entry *rle; + int error; + int avail; + int i; + + avail = pci_msix_count(pdev->dev.bsddev); + if (avail < nreq) { + if (avail == 0) + return -EINVAL; + return avail; + } + avail = nreq; + if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0) + return error; + /* + * Handle case where "pci_alloc_msix()" may allocate less + * interrupts than available and return with no error: + */ + if (avail < nreq) { + pci_release_msi(pdev->dev.bsddev); + return avail; + } + rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false); + pdev->dev.irq_start = rle->start; + pdev->dev.irq_end = rle->start + avail; + for (i = 0; i < nreq; i++) + entries[i].vector = pdev->dev.irq_start + i; + pdev->msix_enabled = true; + return (0); +} + +int +_lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec) +{ + struct resource_list_entry *rle; + int error; + int nvec; + + if (maxvec < minvec) + return (-EINVAL); + + nvec = pci_msi_count(pdev->dev.bsddev); + if (nvec < 1 || nvec < minvec) + return (-ENOSPC); + + nvec = min(nvec, maxvec); + if ((error = -pci_alloc_msi(pdev->dev.bsddev, &nvec)) != 0) + return error; + + /* Native PCI might only ever ask for 32 vectors. */ + if (nvec < minvec) { + pci_release_msi(pdev->dev.bsddev); + return (-ENOSPC); + } + + rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false); + pdev->dev.irq_start = rle->start; + pdev->dev.irq_end = rle->start + nvec; + pdev->irq = rle->start; + pdev->msi_enabled = true; + return (0); +} + int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv, unsigned int flags) @@ -986,7 +1308,7 @@ struct pcicfg_msi *msi; int vec; - dev = linux_pci_find_irq_dev(irq); + dev = lkpi_pci_find_irq_dev(irq); if (dev == NULL) return (NULL); diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c --- a/sys/compat/linuxkpi/common/src/linux_work.c +++ b/sys/compat/linuxkpi/common/src/linux_work.c @@ -360,6 +360,38 @@ } } +/* + * This function cancels the given work structure in a + * non-blocking fashion. It returns non-zero if the work was + * successfully cancelled. Else the work may still be busy or already + * cancelled. + */ +bool +linux_cancel_work(struct work_struct *work) +{ + static const uint8_t states[WORK_ST_MAX] __aligned(8) = { + [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */ + [WORK_ST_TIMER] = WORK_ST_TIMER, /* can't happen */ + [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel */ + [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */ + [WORK_ST_CANCEL] = WORK_ST_IDLE, /* can't happen */ + }; + struct taskqueue *tq; + + MPASS(atomic_read(&work->state) != WORK_ST_TIMER); + MPASS(atomic_read(&work->state) != WORK_ST_CANCEL); + + switch (linux_update_state(&work->state, states)) { + case WORK_ST_TASK: + tq = work->work_queue->taskqueue; + if (taskqueue_cancel(tq, &work->work_task, NULL) == 0) + return (true); + /* FALLTHROUGH */ + default: + return (false); + } +} + /* * This function cancels the given work structure in a synchronous * fashion. It returns non-zero if the work was successfully diff --git a/sys/compat/linuxkpi/dummy/include/asm/hypervisor.h b/sys/compat/linuxkpi/dummy/include/asm/neon.h rename from sys/compat/linuxkpi/dummy/include/asm/hypervisor.h rename to sys/compat/linuxkpi/dummy/include/asm/neon.h diff --git a/sys/compat/linuxkpi/dummy/include/linux/ioport.h b/sys/compat/linuxkpi/dummy/include/linux/dev_printk.h rename from sys/compat/linuxkpi/dummy/include/linux/ioport.h rename to sys/compat/linuxkpi/dummy/include/linux/dev_printk.h diff --git a/sys/compat/linuxkpi/dummy/include/linux/irqdomain.h b/sys/compat/linuxkpi/dummy/include/linux/device/bus.h rename from sys/compat/linuxkpi/dummy/include/linux/irqdomain.h rename to sys/compat/linuxkpi/dummy/include/linux/device/bus.h diff --git a/sys/compat/linuxkpi/dummy/include/video/vga.h b/sys/compat/linuxkpi/dummy/include/linux/mei_aux.h rename from sys/compat/linuxkpi/dummy/include/video/vga.h rename to sys/compat/linuxkpi/dummy/include/linux/mei_aux.h diff --git a/sys/compat/linuxkpi/dummy/include/asm/hypervisor.h b/sys/compat/linuxkpi/dummy/include/linux/prandom.h copy from sys/compat/linuxkpi/dummy/include/asm/hypervisor.h copy to sys/compat/linuxkpi/dummy/include/linux/prandom.h diff --git a/sys/compat/linuxkpi/dummy/include/asm/hypervisor.h b/sys/compat/linuxkpi/dummy/include/linux/sysfb.h copy from sys/compat/linuxkpi/dummy/include/asm/hypervisor.h copy to sys/compat/linuxkpi/dummy/include/linux/sysfb.h diff --git a/sys/compat/linuxkpi/dummy/include/asm/hypervisor.h b/sys/compat/linuxkpi/dummy/include/video/nomodeset.h rename from sys/compat/linuxkpi/dummy/include/asm/hypervisor.h rename to sys/compat/linuxkpi/dummy/include/video/nomodeset.h diff --git a/sys/contrib/dev/iwlwifi/pcie/trans.c b/sys/contrib/dev/iwlwifi/pcie/trans.c --- a/sys/contrib/dev/iwlwifi/pcie/trans.c +++ b/sys/contrib/dev/iwlwifi/pcie/trans.c @@ -15,6 +15,7 @@ #include #include #if defined(__FreeBSD__) +#include #include #endif diff --git a/sys/contrib/dev/rtw88/pci.c b/sys/contrib/dev/rtw88/pci.c --- a/sys/contrib/dev/rtw88/pci.c +++ b/sys/contrib/dev/rtw88/pci.c @@ -17,6 +17,7 @@ #include "ps.h" #include "debug.h" #if defined(__FreeBSD__) +#include #include #endif diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -512,6 +512,9 @@ enable_idle(struct acpi_cpu_softc *sc) { + if (sc->cpu_cx_count > sc->cpu_non_c3 + 1 && + (cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0) + AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 1); sc->cpu_disable_idle = FALSE; } @@ -1164,14 +1167,13 @@ } /* - * For C3, disable bus master arbitration and enable bus master wake - * if BM control is available, otherwise flush the CPU cache. + * For C3, disable bus master arbitration if BM control is available. + * CPU may have to wake up to handle it. Otherwise flush the CPU cache. */ if (cx_next->type == ACPI_STATE_C3) { - if ((cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0) { + if ((cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0) AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 1); - AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 1); - } else + else ACPI_FLUSH_CPU_CACHE(); } @@ -1206,12 +1208,10 @@ else end_ticks = cpu_ticks(); - /* Enable bus master arbitration and disable bus master wakeup. */ + /* Enable bus master arbitration. */ if (cx_next->type == ACPI_STATE_C3 && - (cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0) { + (cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0) AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 0); - AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 0); - } ACPI_ENABLE_IRQS(); if (cx_next->type == ACPI_STATE_C3) diff --git a/sys/dev/acpica/acpi_lid.c b/sys/dev/acpica/acpi_lid.c --- a/sys/dev/acpica/acpi_lid.c +++ b/sys/dev/acpica/acpi_lid.c @@ -91,7 +91,7 @@ DRIVER_MODULE(acpi_lid, acpi, acpi_lid_driver, 0, 0); MODULE_DEPEND(acpi_lid, acpi, 1, 1, 1); -static void +static int acpi_lid_status_update(struct acpi_lid_softc *sc) { ACPI_STATUS status; @@ -107,9 +107,12 @@ status = acpi_GetInteger(sc->lid_handle, "_LID", &lid_status); if (ACPI_FAILURE(status)) lid_status = 1; /* assume lid is opened */ + else + lid_status = (lid_status != 0); /* range check value */ - /* range check value */ - sc->lid_status = lid_status ? 1 : 0; + if (sc->lid_status == lid_status) + return (EALREADY); + sc->lid_status = lid_status; /* Send notification via devd */ acpi_UserNotify("Lid", sc->lid_handle, sc->lid_status); @@ -119,6 +122,7 @@ evdev_push_sw(sc->lid_evdev, SW_LID, lid_status ? 0 : 1); evdev_sync(sc->lid_evdev); #endif + return (0); } static int @@ -146,6 +150,7 @@ sc = device_get_softc(dev); sc->lid_dev = dev; acpi_lid_handle = sc->lid_handle = acpi_get_handle(dev); + sc->lid_status = -1; #ifdef EVDEV_SUPPORT /* Register evdev device before initial status update */ @@ -219,7 +224,8 @@ ACPI_SERIAL_BEGIN(lid); /* Update lid status, if any */ - acpi_lid_status_update(sc); + if (acpi_lid_status_update(sc) != 0) + goto out; acpi_sc = acpi_device_get_parent_softc(sc->lid_dev); if (acpi_sc == NULL) @@ -228,8 +234,6 @@ ACPI_VPRINT(sc->lid_dev, acpi_sc, "Lid %s\n", sc->lid_status ? "opened" : "closed"); - acpi_UserNotify("Lid", sc->lid_handle, sc->lid_status); - if (sc->lid_status == 0) EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx); else diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c --- a/sys/dev/ath/ath_rate/sample/sample.c +++ b/sys/dev/ath/ath_rate/sample/sample.c @@ -1433,11 +1433,13 @@ const HAL_RATE_TABLE *rt = sc->sc_currates; struct ath_rateioctl_tlv av; struct ath_rateioctl_rt *tv; - int y; + int error, y; int o = 0; ATH_NODE_LOCK_ASSERT(an); + error = 0; + /* * Ensure there's enough space for the statistics. */ @@ -1478,9 +1480,13 @@ */ av.tlv_id = ATH_RATE_TLV_RATETABLE; av.tlv_len = sizeof(struct ath_rateioctl_rt); - copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); + error = copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); + if (error != 0) + goto out; o += sizeof(struct ath_rateioctl_tlv); - copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); + error = copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt)); + if (error != 0) + goto out; o += sizeof(struct ath_rateioctl_rt); /* @@ -1488,18 +1494,22 @@ */ av.tlv_id = ATH_RATE_TLV_SAMPLENODE; av.tlv_len = sizeof(struct sample_node); - copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); + error = copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv)); + if (error != 0) + goto out; o += sizeof(struct ath_rateioctl_tlv); /* * Copy the statistics over to the provided buffer. */ - copyout(sn, rs->buf + o, sizeof(struct sample_node)); + error = copyout(sn, rs->buf + o, sizeof(struct sample_node)); + if (error != 0) + goto out; o += sizeof(struct sample_node); +out: free(tv, M_TEMP); - - return (0); + return (error); } static void diff --git a/sys/dev/drm2/ttm/ttm_bo.c b/sys/dev/drm2/ttm/ttm_bo.c --- a/sys/dev/drm2/ttm/ttm_bo.c +++ b/sys/dev/drm2/ttm/ttm_bo.c @@ -1498,8 +1498,8 @@ VM_MAX_ADDRESS, PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE); if (unlikely(glob->dummy_read_page == NULL)) { - if (tries < 1 && vm_page_reclaim_contig(0, 1, 0, - VM_MAX_ADDRESS, PAGE_SIZE, 0)) { + if (tries < 1 && (vm_page_reclaim_contig(0, 1, 0, + VM_MAX_ADDRESS, PAGE_SIZE, 0) == 0)) { tries++; goto retry; } diff --git a/sys/dev/drm2/ttm/ttm_page_alloc.c b/sys/dev/drm2/ttm/ttm_page_alloc.c --- a/sys/dev/drm2/ttm/ttm_page_alloc.c +++ b/sys/dev/drm2/ttm/ttm_page_alloc.c @@ -158,16 +158,19 @@ ttm_vm_page_alloc_dma32(int req, vm_memattr_t memattr) { vm_page_t p; - int tries; + int err, tries; for (tries = 0; ; tries++) { p = vm_page_alloc_noobj_contig(req, 1, 0, 0xffffffff, PAGE_SIZE, 0, memattr); if (p != NULL || tries > 2) return (p); - if (!vm_page_reclaim_contig(req, 1, 0, 0xffffffff, - PAGE_SIZE, 0)) + err = vm_page_reclaim_contig(req, 1, 0, 0xffffffff, + PAGE_SIZE, 0); + if (err == ENOMEM) vm_wait(NULL); + else if (err != 0) + return (NULL); } } diff --git a/sys/dev/hid/hidraw.c b/sys/dev/hid/hidraw.c --- a/sys/dev/hid/hidraw.c +++ b/sys/dev/hid/hidraw.c @@ -674,13 +674,16 @@ sc->sc_state.quiet = true; mtx_unlock(&sc->sc_mtx); if (error != 0) - return(error); + return (error); buf = HIDRAW_LOCAL_ALLOC(local_buf, hgd->hgd_maxlen); - copyin(hgd->hgd_data, buf, hgd->hgd_maxlen); - bus_topo_lock(); - error = hid_set_report_descr(sc->sc_dev, buf, hgd->hgd_maxlen); - bus_topo_unlock(); + error = copyin(hgd->hgd_data, buf, hgd->hgd_maxlen); + if (error == 0) { + bus_topo_lock(); + error = hid_set_report_descr(sc->sc_dev, buf, + hgd->hgd_maxlen); + bus_topo_unlock(); + } HIDRAW_LOCAL_FREE(local_buf, buf); /* Realloc hidraw input queue */ @@ -737,8 +740,11 @@ default: return (EINVAL); } - if (id != 0) - copyin(hgd->hgd_data, &id, 1); + if (id != 0) { + error = copyin(hgd->hgd_data, &id, 1); + if (error != 0) + return (error); + } size = MIN(hgd->hgd_maxlen, size); buf = HIDRAW_LOCAL_ALLOC(local_buf, size); error = hid_get_report(sc->sc_dev, buf, size, NULL, @@ -775,11 +781,13 @@ } size = MIN(hgd->hgd_maxlen, size); buf = HIDRAW_LOCAL_ALLOC(local_buf, size); - copyin(hgd->hgd_data, buf, size); - if (id != 0) - id = *(uint8_t *)buf; - error = hid_set_report(sc->sc_dev, buf, size, - hgd->hgd_report_type, id); + error = copyin(hgd->hgd_data, buf, size); + if (error == 0) { + if (id != 0) + id = *(uint8_t *)buf; + error = hid_set_report(sc->sc_dev, buf, size, + hgd->hgd_report_type, id); + } HIDRAW_LOCAL_FREE(local_buf, buf); return (error); diff --git a/sys/dev/ichiic/ig4_iic.c b/sys/dev/ichiic/ig4_iic.c --- a/sys/dev/ichiic/ig4_iic.c +++ b/sys/dev/ichiic/ig4_iic.c @@ -350,6 +350,7 @@ /* * Wait for TXFIFO to drain before disabling the controller. */ + reg_write(sc, IG4_REG_TX_TL, 0); wait_intr(sc, IG4_INTR_TX_EMPTY); set_controller(sc, 0); @@ -437,16 +438,20 @@ return (0); while (received < len) { + /* Ensure we have some free space in TXFIFO */ burst = sc->cfg.txfifo_depth - (reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK); if (burst <= 0) { + reg_write(sc, IG4_REG_TX_TL, IG4_FIFO_LOWAT); error = wait_intr(sc, IG4_INTR_TX_EMPTY); if (error) break; - burst = sc->cfg.txfifo_depth; + burst = sc->cfg.txfifo_depth - + (reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK); } /* Ensure we have enough free space in RXFIFO */ - burst = MIN(burst, sc->cfg.rxfifo_depth - lowat); + burst = MIN(burst, sc->cfg.rxfifo_depth - + (requested - received)); target = MIN(requested + burst, (int)len); while (requested < target) { cmd = IG4_DATA_COMMAND_RD; @@ -463,13 +468,15 @@ lowat = IG4_FIFO_LOWAT; /* After TXFLR fills up, clear it by reading available data */ while (received < requested - lowat) { - burst = MIN((int)len - received, + burst = MIN(requested - received, reg_read(sc, IG4_REG_RXFLR) & IG4_FIFOLVL_MASK); if (burst > 0) { while (burst--) buf[received++] = 0xFF & reg_read(sc, IG4_REG_DATA_CMD); } else { + reg_write(sc, IG4_REG_RX_TL, + requested - received - lowat - 1); error = wait_intr(sc, IG4_INTR_RX_FULL); if (error) goto out; @@ -487,8 +494,7 @@ uint32_t cmd; int sent = 0; int burst, target; - int error; - bool lowat_set = false; + int error, lowat; if (len == 0) return (0); @@ -497,12 +503,7 @@ burst = sc->cfg.txfifo_depth - (reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK); target = MIN(sent + burst, (int)len); - /* Leave some data queued to maintain the hardware pipeline */ - if (!lowat_set && target != len) { - lowat_set = true; - reg_write(sc, IG4_REG_TX_TL, IG4_FIFO_LOWAT); - } - while(sent < target) { + while (sent < target) { cmd = buf[sent]; if (repeated_start && sent == 0) cmd |= IG4_DATA_RESTART; @@ -512,13 +513,16 @@ sent++; } if (sent < len) { + if (len - sent <= sc->cfg.txfifo_depth) + lowat = sc->cfg.txfifo_depth - (len - sent); + else + lowat = IG4_FIFO_LOWAT; + reg_write(sc, IG4_REG_TX_TL, lowat); error = wait_intr(sc, IG4_INTR_TX_EMPTY); if (error) break; } } - if (lowat_set) - reg_write(sc, IG4_REG_TX_TL, 0); return (error); } @@ -850,23 +854,6 @@ sc->cfg.txfifo_depth = IG4_PARAM1_TXFIFO_DEPTH(v); if (IG4_PARAM1_RXFIFO_DEPTH(v) != 0) sc->cfg.rxfifo_depth = IG4_PARAM1_RXFIFO_DEPTH(v); - } else { - /* - * Hardware does not allow FIFO Threshold Levels value to be - * set larger than the depth of the buffer. If an attempt is - * made to do that, the actual value set will be the maximum - * depth of the buffer. - */ - v = reg_read(sc, IG4_REG_TX_TL); - reg_write(sc, IG4_REG_TX_TL, v | IG4_FIFO_MASK); - sc->cfg.txfifo_depth = - (reg_read(sc, IG4_REG_TX_TL) & IG4_FIFO_MASK) + 1; - reg_write(sc, IG4_REG_TX_TL, v); - v = reg_read(sc, IG4_REG_RX_TL); - reg_write(sc, IG4_REG_RX_TL, v | IG4_FIFO_MASK); - sc->cfg.rxfifo_depth = - (reg_read(sc, IG4_REG_RX_TL) & IG4_FIFO_MASK) + 1; - reg_write(sc, IG4_REG_RX_TL, v); } /* Override hardware config with IC_clock-based counter values */ @@ -918,8 +905,6 @@ printf(" Fast: 0x%04hx:0x%04hx:0x%04hx\n", sc->cfg.fs_scl_hcnt, sc->cfg.fs_scl_lcnt, sc->cfg.fs_sda_hold); - printf(" FIFO: RX:0x%04x: TX:0x%04x\n", - sc->cfg.rxfifo_depth, sc->cfg.txfifo_depth); } } @@ -993,13 +978,6 @@ (sc->cfg.bus_speed & IG4_CTL_SPEED_MASK) == IG4_CTL_SPEED_STD ? sc->cfg.ss_sda_hold : sc->cfg.fs_sda_hold); - /* - * Use a threshold of 1 so we get interrupted on each character, - * allowing us to use mtx_sleep() in our poll code. Not perfect - * but this is better than using DELAY() for receiving data. - * - * See ig4_var.h for details on interrupt handler synchronization. - */ reg_write(sc, IG4_REG_RX_TL, 0); reg_write(sc, IG4_REG_TX_TL, 0); @@ -1015,6 +993,36 @@ return (0); } +static void +ig4iic_get_fifo(ig4iic_softc_t *sc) +{ + uint32_t v; + + /* + * Hardware does not allow FIFO Threshold Levels value to be set larger + * than the depth of the buffer. If an attempt is made to do that, the + * actual value set will be the maximum depth of the buffer. + */ + if (sc->cfg.txfifo_depth == 0) { + v = reg_read(sc, IG4_REG_TX_TL); + reg_write(sc, IG4_REG_TX_TL, v | IG4_FIFO_MASK); + sc->cfg.txfifo_depth = + (reg_read(sc, IG4_REG_TX_TL) & IG4_FIFO_MASK) + 1; + reg_write(sc, IG4_REG_TX_TL, v); + } + if (sc->cfg.rxfifo_depth == 0) { + v = reg_read(sc, IG4_REG_RX_TL); + reg_write(sc, IG4_REG_RX_TL, v | IG4_FIFO_MASK); + sc->cfg.rxfifo_depth = + (reg_read(sc, IG4_REG_RX_TL) & IG4_FIFO_MASK) + 1; + reg_write(sc, IG4_REG_RX_TL, v); + } + if (bootverbose) { + printf(" FIFO: RX:0x%04x: TX:0x%04x\n", + sc->cfg.rxfifo_depth, sc->cfg.txfifo_depth); + } +} + /* * Called from ig4iic_pci_attach/detach() */ @@ -1031,6 +1039,7 @@ error = ig4iic_set_config(sc, IG4_HAS_ADDREGS(sc->version)); if (error) goto done; + ig4iic_get_fifo(sc); sc->iicbus = device_add_child(sc->dev, "iicbus", -1); if (sc->iicbus == NULL) { diff --git a/sys/dev/iicbus/iicbb.c b/sys/dev/iicbus/iicbb.c --- a/sys/dev/iicbus/iicbb.c +++ b/sys/dev/iicbus/iicbb.c @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef FDT #include @@ -254,11 +255,12 @@ do { if (I2C_GETSCL(dev)) return (0); + cpu_spinwait(); now = sbinuptime(); } while (now < fast_timeout); do { I2C_DEBUG(printf(".")); - pause_sbt("iicbb-scl-low", SBT_1MS, C_PREL(8), 0); + pause_sbt("iicbb-scl-low", SBT_1MS, 0, C_PREL(2)); if (I2C_GETSCL(dev)) return (0); now = sbinuptime(); diff --git a/sys/dev/iicbus/iichid.c b/sys/dev/iicbus/iichid.c --- a/sys/dev/iicbus/iichid.c +++ b/sys/dev/iicbus/iichid.c @@ -106,9 +106,9 @@ * sampling_rate_fast value too high as it may result in periodical lags of * cursor motion. */ -#define IICHID_SAMPLING_RATE_FAST 60 +#define IICHID_SAMPLING_RATE_FAST 80 #define IICHID_SAMPLING_RATE_SLOW 10 -#define IICHID_SAMPLING_HYSTERESIS 1 +#define IICHID_SAMPLING_HYSTERESIS 16 /* ~ 2x fast / slow */ /* 5.1.1 - HID Descriptor Format */ struct i2c_hid_desc { @@ -177,9 +177,12 @@ int sampling_rate_fast; int sampling_hysteresis; int missing_samples; /* iicbus lock */ - struct timeout_task periodic_task; /* iicbus lock */ + int dup_samples; /* iicbus lock */ + iichid_size_t dup_size; /* iicbus lock */ bool callout_setup; /* iicbus lock */ + uint8_t *dup_buf; struct taskqueue *taskqueue; + struct timeout_task periodic_task; /* iicbus lock */ struct task event_task; #endif @@ -523,7 +526,7 @@ device_t parent; iichid_size_t actual; bool bus_requested; - int error; + int error, rate; sc = context; parent = device_get_parent(sc->dev); @@ -541,18 +544,30 @@ if (actual > 0) { sc->intr_handler(sc->intr_ctx, sc->intr_buf, actual); sc->missing_samples = 0; - } else - ++sc->missing_samples; + if (sc->dup_size != actual || + memcmp(sc->dup_buf, sc->intr_buf, actual) != 0) { + sc->dup_size = actual; + memcpy(sc->dup_buf, sc->intr_buf, actual); + sc->dup_samples = 0; + } else + ++sc->dup_samples; + } else { + if (++sc->missing_samples == 1) + sc->intr_handler(sc->intr_ctx, sc->intr_buf, 0); + sc->dup_samples = 0; + } } else DPRINTF(sc, "read error occurred: %d\n", error); rearm: if (sc->callout_setup && sc->sampling_rate_slow > 0) { - if (sc->missing_samples == sc->sampling_hysteresis) - sc->intr_handler(sc->intr_ctx, sc->intr_buf, 0); - taskqueue_enqueue_timeout(sc->taskqueue, &sc->periodic_task, - hz / MAX(sc->missing_samples >= sc->sampling_hysteresis ? - sc->sampling_rate_slow : sc->sampling_rate_fast, 1)); + if (sc->missing_samples >= sc->sampling_hysteresis || + sc->dup_samples >= sc->sampling_hysteresis) + rate = sc->sampling_rate_slow; + else + rate = sc->sampling_rate_fast; + taskqueue_enqueue_timeout_sbt(sc->taskqueue, &sc->periodic_task, + SBT_1S / MAX(rate, 1), 0, C_PREL(2)); } out: if (bus_requested) @@ -725,6 +740,8 @@ /* Start with slow sampling. */ sc->missing_samples = sc->sampling_hysteresis; + sc->dup_samples = 0; + sc->dup_size = 0; taskqueue_enqueue(sc->taskqueue, &sc->event_task); return (0); @@ -812,6 +829,7 @@ sc->intr_buf = malloc(rdesc->rdsize, M_DEVBUF, M_WAITOK | M_ZERO); sc->intr_bufsize = rdesc->rdsize; #ifdef IICHID_SAMPLING + sc->dup_buf = malloc(rdesc->rdsize, M_DEVBUF, M_WAITOK | M_ZERO); taskqueue_start_threads(&sc->taskqueue, 1, PI_TTY, "%s taskq", device_get_nameunit(sc->dev)); #endif @@ -825,6 +843,7 @@ sc = device_get_softc(dev); #ifdef IICHID_SAMPLING taskqueue_drain_all(sc->taskqueue); + free(sc->dup_buf, M_DEVBUF); #endif free(sc->intr_buf, M_DEVBUF); } diff --git a/sys/dev/iommu/iommu_gas.h b/sys/dev/iommu/iommu_gas.h --- a/sys/dev/iommu/iommu_gas.h +++ b/sys/dev/iommu/iommu_gas.h @@ -50,6 +50,7 @@ #define IOMMU_MAP_ENTRY_UNMAPPED 0x0010 /* No backing pages */ #define IOMMU_MAP_ENTRY_REMOVING 0x0020 /* In process of removal by iommu_gas_remove() */ +#define IOMMU_MAP_ENTRY_FAKE 0x0040 /* disable assert in cmp() */ #define IOMMU_MAP_ENTRY_READ 0x1000 /* Read permitted */ #define IOMMU_MAP_ENTRY_WRITE 0x2000 /* Write permitted */ #define IOMMU_MAP_ENTRY_SNOOP 0x4000 /* Snoop */ diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c --- a/sys/dev/iommu/iommu_gas.c +++ b/sys/dev/iommu/iommu_gas.c @@ -28,7 +28,6 @@ * SUCH DAMAGE. */ -#include #define RB_AUGMENT_CHECK(entry) iommu_gas_augment_entry(entry) #include @@ -119,16 +118,19 @@ iommu_gas_cmp_entries(struct iommu_map_entry *a, struct iommu_map_entry *b) { - /* Last entry have zero size, so <= */ + /* First and last entries have zero size, so <= */ KASSERT(a->start <= a->end, ("inverted entry %p (%jx, %jx)", a, (uintmax_t)a->start, (uintmax_t)a->end)); KASSERT(b->start <= b->end, ("inverted entry %p (%jx, %jx)", b, (uintmax_t)b->start, (uintmax_t)b->end)); - KASSERT(a->end <= b->start || b->end <= a->start || + KASSERT(((a->flags | b->flags) & IOMMU_MAP_ENTRY_FAKE) != 0 || + a->end <= b->start || b->end <= a->start || a->end == a->start || b->end == b->start, - ("overlapping entries %p (%jx, %jx) %p (%jx, %jx)", - a, (uintmax_t)a->start, (uintmax_t)a->end, - b, (uintmax_t)b->start, (uintmax_t)b->end)); + ("overlapping entries %p (%jx, %jx) f %#x %p (%jx, %jx) f %#x" + " domain %p %p", + a, (uintmax_t)a->start, (uintmax_t)a->end, a->flags, + b, (uintmax_t)b->start, (uintmax_t)b->end, b->flags, + a->domain, b->domain)); if (a->end < b->end) return (-1); @@ -242,25 +244,17 @@ KASSERT(RB_EMPTY(&domain->rb_root), ("non-empty entries %p", domain)); - /* - * The end entry must be inserted first because it has a zero-length gap - * between start and end. Initially, all augmentation data for a new - * entry is zero. Function iommu_gas_augment_entry will compute no - * change in the value of (start-end) and no change in the value of - * free_down, so it will return false to suggest that nothing changed in - * the entry. Thus, inserting the end entry second prevents - * augmentation information to be propogated to the begin entry at the - * tree root. So it is inserted first. - */ end->start = domain->end; end->end = domain->end; end->flags = IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_UNMAPPED; RB_INSERT(iommu_gas_entries_tree, &domain->rb_root, end); begin->start = 0; - begin->end = IOMMU_PAGE_SIZE; + begin->end = 0; begin->flags = IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_UNMAPPED; RB_INSERT_PREV(iommu_gas_entries_tree, &domain->rb_root, end, begin); + iommu_gas_augment_entry(end); + iommu_gas_augment_entry(begin); domain->start_gap = begin; domain->first_place = begin; @@ -330,6 +324,8 @@ start = roundup2(beg, a->common->alignment); if (start < beg) return (false); + if (end < IOMMU_PAGE_SIZE + 1) + return (false); end = MIN(end - IOMMU_PAGE_SIZE - 1, ubound); offset = a->offset; size = a->size; @@ -533,11 +529,13 @@ if (entry->end >= domain->end) return (EINVAL); + entry->flags |= IOMMU_MAP_ENTRY_FAKE; next = RB_NFIND(iommu_gas_entries_tree, &domain->rb_root, entry); KASSERT(next != NULL, ("next must be non-null %p %jx", domain, (uintmax_t)entry->start)); prev = RB_PREV(iommu_gas_entries_tree, &domain->rb_root, next); /* prev could be NULL */ + entry->flags &= ~IOMMU_MAP_ENTRY_FAKE; /* * Adapt to broken BIOSes which specify overlapping RMRR @@ -652,8 +650,10 @@ * asserted that start is below domain end, entry should * exist. Then clip it if needed. */ + bzero(&fentry, sizeof(fentry)); fentry.start = start + 1; fentry.end = start + 1; + fentry.flags = IOMMU_MAP_ENTRY_FAKE; entry = RB_NFIND(iommu_gas_entries_tree, &domain->rb_root, &fentry); if (entry->start >= start || @@ -693,6 +693,7 @@ IOMMU_DOMAIN_ASSERT_LOCKED(domain); if ((entry->flags & (IOMMU_MAP_ENTRY_UNMAPPED | + IOMMU_MAP_ENTRY_RMRR | IOMMU_MAP_ENTRY_REMOVING)) != 0) return; MPASS((entry->flags & IOMMU_MAP_ENTRY_PLACE) == 0); @@ -700,46 +701,37 @@ TAILQ_INSERT_TAIL(gcp, entry, dmamap_link); } -/* - * Remove specified range from the GAS of the domain. Note that the - * removal is not guaranteed to occur upon the function return, it - * might be finalized some time after, when hardware reports that - * (queued) IOTLB invalidation was performed. - */ -void -iommu_gas_remove(struct iommu_domain *domain, iommu_gaddr_t start, - iommu_gaddr_t size) +static void +iommu_gas_remove_locked(struct iommu_domain *domain, + iommu_gaddr_t start, iommu_gaddr_t size, + struct iommu_map_entries_tailq *gc, + struct iommu_map_entry **r1, struct iommu_map_entry **r2) { - struct iommu_map_entry *entry, *nentry, *r1, *r2; - struct iommu_map_entries_tailq gc; + struct iommu_map_entry *entry, *nentry; iommu_gaddr_t end; - end = start + size; - r1 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); - r2 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); - TAILQ_INIT(&gc); + IOMMU_DOMAIN_ASSERT_LOCKED(domain); - IOMMU_DOMAIN_LOCK(domain); + end = start + size; - nentry = iommu_gas_remove_clip_left(domain, start, end, &r1); + nentry = iommu_gas_remove_clip_left(domain, start, end, r1); RB_FOREACH_FROM(entry, iommu_gas_entries_tree, nentry) { if (entry->start >= end) break; KASSERT(start <= entry->start, ("iommu_gas_remove entry (%#jx, %#jx) start %#jx", entry->start, entry->end, start)); - if ((entry->flags & IOMMU_MAP_ENTRY_RMRR) != 0) - continue; - iommu_gas_remove_unmap(domain, entry, &gc); + iommu_gas_remove_unmap(domain, entry, gc); } - if (iommu_gas_remove_clip_right(domain, end, entry, r2)) { - iommu_gas_remove_unmap(domain, r2, &gc); - r2 = NULL; + if (iommu_gas_remove_clip_right(domain, end, entry, *r2)) { + iommu_gas_remove_unmap(domain, *r2, gc); + *r2 = NULL; } #ifdef INVARIANTS RB_FOREACH(entry, iommu_gas_entries_tree, &domain->rb_root) { - if ((entry->flags & IOMMU_MAP_ENTRY_RMRR) != 0) + if ((entry->flags & (IOMMU_MAP_ENTRY_RMRR | + IOMMU_MAP_ENTRY_PLACE)) != 0) continue; KASSERT(entry->end <= start || entry->start >= end, ("iommu_gas_remove leftover entry (%#jx, %#jx) range " @@ -747,13 +739,52 @@ entry->start, entry->end, start, end)); } #endif +} + +static void +iommu_gas_remove_init(struct iommu_domain *domain, + struct iommu_map_entries_tailq *gc, struct iommu_map_entry **r1, + struct iommu_map_entry **r2) +{ + TAILQ_INIT(gc); + *r1 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); + *r2 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); +} + +static void +iommu_gas_remove_cleanup(struct iommu_domain *domain, + struct iommu_map_entries_tailq *gc, struct iommu_map_entry **r1, + struct iommu_map_entry **r2) +{ + if (*r1 != NULL) { + iommu_gas_free_entry(*r1); + *r1 = NULL; + } + if (*r2 != NULL) { + iommu_gas_free_entry(*r2); + *r2 = NULL; + } + iommu_domain_unload(domain, gc, true); +} + +/* + * Remove specified range from the GAS of the domain. Note that the + * removal is not guaranteed to occur upon the function return, it + * might be finalized some time after, when hardware reports that + * (queued) IOTLB invalidation was performed. + */ +void +iommu_gas_remove(struct iommu_domain *domain, iommu_gaddr_t start, + iommu_gaddr_t size) +{ + struct iommu_map_entry *r1, *r2; + struct iommu_map_entries_tailq gc; + iommu_gas_remove_init(domain, &gc, &r1, &r2); + IOMMU_DOMAIN_LOCK(domain); + iommu_gas_remove_locked(domain, start, size, &gc, &r1, &r2); IOMMU_DOMAIN_UNLOCK(domain); - if (r1 != NULL) - iommu_gas_free_entry(r1); - if (r2 != NULL) - iommu_gas_free_entry(r2); - iommu_domain_unload(domain, &gc, true); + iommu_gas_remove_cleanup(domain, &gc, &r1, &r2); } int @@ -1030,3 +1061,48 @@ &iommu_check_free, 0, "Check the GPA RBtree for free_down and free_after validity"); #endif + +#include "opt_ddb.h" +#ifdef DDB + +#include + +static void +iommu_debug_dump_gas(struct iommu_domain *domain) +{ + struct iommu_map_entry *entry; + + db_printf("iommu_domain %p tree %p iommu %p fl %#x\n", domain, + &domain->rb_root, domain->iommu, domain->flags); + db_printf("iommu_domain %p tree %p\n", domain, &domain->rb_root); + RB_FOREACH(entry, iommu_gas_entries_tree, &domain->rb_root) { + db_printf( + " e %p [%#jx %#jx] fl %#x first %#jx last %#jx free_down %#jx", + entry, (uintmax_t)entry->start, (uintmax_t)entry->end, + entry->flags, + (uintmax_t)entry->first, (uintmax_t)entry->last, + (uintmax_t)entry->free_down); + if (entry == domain->start_gap) + db_printf(" start_gap"); + if (entry == domain->first_place) + db_printf(" first_place"); + if (entry == domain->last_place) + db_printf(" last_place"); + db_printf("\n"); + } +} + +DB_SHOW_COMMAND(iommu_domain, iommu_domain_show) +{ + struct iommu_domain *domain; + + if (!have_addr) { + db_printf("show iommu_domain addr\n"); + return; + } + + domain = (void *)addr; + iommu_debug_dump_gas(domain); +} + +#endif diff --git a/sys/dev/irdma/irdma_main.h b/sys/dev/irdma/irdma_main.h --- a/sys/dev/irdma/irdma_main.h +++ b/sys/dev/irdma/irdma_main.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c --- a/sys/dev/iscsi/iscsi.c +++ b/sys/dev/iscsi/iscsi.c @@ -1896,17 +1896,17 @@ return (EMSGSIZE); } - copyout(ip->ip_bhs, idr->idr_bhs, sizeof(*ip->ip_bhs)); - if (ip->ip_data_len > 0) { + error = copyout(ip->ip_bhs, idr->idr_bhs, sizeof(*ip->ip_bhs)); + if (error == 0 && ip->ip_data_len > 0) { data = malloc(ip->ip_data_len, M_ISCSI, M_WAITOK); icl_pdu_get_data(ip, 0, data, ip->ip_data_len); - copyout(data, idr->idr_data_segment, ip->ip_data_len); + error = copyout(data, idr->idr_data_segment, ip->ip_data_len); free(data, M_ISCSI); } icl_pdu_free(ip); - return (0); + return (error); } #endif /* ICL_KERNEL_PROXY */ diff --git a/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c b/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c --- a/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c +++ b/sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c @@ -2293,7 +2293,6 @@ dev_addr[ETHER_ADDR_LEN - 1 - i] = (u8) (priv->mac >> (8 * i)); - ether_ifattach(dev, dev_addr); if_link_state_change(dev, LINK_STATE_DOWN); ifmedia_init(&priv->media, IFM_IMASK | IFM_ETH_FMASK, mlx4_en_media_change, mlx4_en_media_status); @@ -2306,6 +2305,8 @@ DEBUGNET_SET(dev, mlx4_en); + ether_ifattach(dev, dev_addr); + en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); diff --git a/sys/dev/mpi3mr/mpi3mr_app.c b/sys/dev/mpi3mr/mpi3mr_app.c --- a/sys/dev/mpi3mr/mpi3mr_app.c +++ b/sys/dev/mpi3mr/mpi3mr_app.c @@ -543,6 +543,7 @@ { U16 i, needed_desc = (dma_buffers->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE); U32 buf_len = dma_buffers->kern_buf_len, copied_len = 0; + int error; if (dma_buffers->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) needed_desc++; @@ -558,6 +559,7 @@ if (!dma_buffers->dma_desc) return -1; + error = 0; for (i = 0; i < needed_desc; i++, desc_count++) { dma_buffers->dma_desc[i].addr = sc->ioctl_sge[desc_count].addr; @@ -572,12 +574,19 @@ memset(dma_buffers->dma_desc[i].addr, 0, sc->ioctl_sge[desc_count].size); if (dma_buffers->data_dir == MPI3MR_APP_DDO) { - copyin(((U8 *)dma_buffers->user_buf + copied_len), + error = copyin(((U8 *)dma_buffers->user_buf + copied_len), dma_buffers->dma_desc[i].addr, dma_buffers->dma_desc[i].size); + if (error != 0) + break; copied_len += dma_buffers->dma_desc[i].size; } } + if (error != 0) { + printf("%s: DMA copyin error %d\n", __func__, error); + free(dma_buffers->dma_desc, M_MPI3MR); + return -1; + } dma_buffers->num_dma_desc = needed_desc; diff --git a/sys/dev/mpr/mpr_user.c b/sys/dev/mpr/mpr_user.c --- a/sys/dev/mpr/mpr_user.c +++ b/sys/dev/mpr/mpr_user.c @@ -714,9 +714,9 @@ } mpr_unlock(sc); - copyout(rpl, cmd->rpl, sz); - if (buf != NULL) - copyout(buf, cmd->buf, cmd->len); + err = copyout(rpl, cmd->rpl, sz); + if (buf != NULL && err == 0) + err = copyout(buf, cmd->buf, cmd->len); mpr_dprint(sc, MPR_USER, "%s: reply size %d\n", __func__, sz); RetFreeUnlocked: @@ -848,7 +848,7 @@ /* * Copy the reply data and sense data to user space. */ - if ((cm != NULL) && (cm->cm_reply != NULL)) { + if (err == 0 && cm != NULL && cm->cm_reply != NULL) { rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; @@ -858,7 +858,7 @@ __func__, data->ReplySize, sz); } mpr_unlock(sc); - copyout(cm->cm_reply, PTRIN(data->PtrReply), + err = copyout(cm->cm_reply, PTRIN(data->PtrReply), MIN(sz, data->ReplySize)); mpr_lock(sc); } @@ -1073,7 +1073,7 @@ /* * Copy the reply data and sense data to user space. */ - if (cm->cm_reply != NULL) { + if (err == 0 && cm->cm_reply != NULL) { rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; @@ -1083,12 +1083,16 @@ data->ReplySize, sz); } mpr_unlock(sc); - copyout(cm->cm_reply, PTRIN(data->PtrReply), + err = copyout(cm->cm_reply, PTRIN(data->PtrReply), MIN(sz, data->ReplySize)); + if (err != 0) + mpr_dprint(sc, MPR_FAULT, "%s: failed to copy " + "IOCTL data to user space\n", __func__); mpr_lock(sc); - if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || - (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + if (err == 0 && + (function == MPI2_FUNCTION_SCSI_IO_REQUEST || + function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { sense_len = @@ -1096,8 +1100,13 @@ SenseCount)), sizeof(struct scsi_sense_data)); mpr_unlock(sc); - copyout(cm->cm_sense, (PTRIN(data->PtrReply + - sizeof(MPI2_SCSI_IO_REPLY))), sense_len); + err = copyout(cm->cm_sense, + PTRIN(data->PtrReply + + sizeof(MPI2_SCSI_IO_REPLY)), sense_len); + if (err != 0) + mpr_dprint(sc, MPR_FAULT, + "%s: failed to copy IOCTL data to " + "user space\n", __func__); mpr_lock(sc); } } @@ -1116,7 +1125,7 @@ * the same IOCTL structure and sense buffers can be used for * NVMe. */ - if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) { + if (err == 0 && function == MPI2_FUNCTION_NVME_ENCAPSULATED) { if (cm->nvme_error_response == NULL) { mpr_dprint(sc, MPR_INFO, "NVMe Error Response " "buffer is NULL. Response data will not be " @@ -1130,9 +1139,13 @@ sz = MIN(le32toh(nvme_error_reply->ErrorResponseCount), NVME_ERROR_RESPONSE_SIZE); mpr_unlock(sc); - copyout(cm->cm_sense, + err = copyout(cm->cm_sense, (PTRIN(data->PtrReply + sizeof(MPI2_SCSI_IO_REPLY))), sz); + if (err != 0) + mpr_dprint(sc, MPR_FAULT, + "%s: failed to copy IOCTL data to " + "user space\n", __func__); mpr_lock(sc); } } diff --git a/sys/dev/mps/mps_user.c b/sys/dev/mps/mps_user.c --- a/sys/dev/mps/mps_user.c +++ b/sys/dev/mps/mps_user.c @@ -715,9 +715,9 @@ } mps_unlock(sc); - copyout(rpl, cmd->rpl, sz); - if (buf != NULL) - copyout(buf, cmd->buf, cmd->len); + err = copyout(rpl, cmd->rpl, sz); + if (buf != NULL && err == 0) + err = copyout(buf, cmd->buf, cmd->len); mps_dprint(sc, MPS_USER, "%s: reply size %d\n", __func__, sz); RetFreeUnlocked: @@ -847,7 +847,7 @@ /* * Copy the reply data and sense data to user space. */ - if ((cm != NULL) && (cm->cm_reply != NULL)) { + if (err == 0 && cm != NULL && cm->cm_reply != NULL) { rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; @@ -857,8 +857,11 @@ __func__, data->ReplySize, sz); } mps_unlock(sc); - copyout(cm->cm_reply, PTRIN(data->PtrReply), + err = copyout(cm->cm_reply, PTRIN(data->PtrReply), MIN(sz, data->ReplySize)); + if (err != 0) + mps_dprint(sc, MPS_FAULT, + "%s: copyout failed\n", __func__); mps_lock(sc); } mpssas_free_tm(sc, cm); @@ -1001,7 +1004,7 @@ /* * Copy the reply data and sense data to user space. */ - if (cm->cm_reply != NULL) { + if (err == 0 && cm->cm_reply != NULL) { rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; sz = rpl->MsgLength * 4; @@ -1011,12 +1014,16 @@ data->ReplySize, sz); } mps_unlock(sc); - copyout(cm->cm_reply, PTRIN(data->PtrReply), + err = copyout(cm->cm_reply, PTRIN(data->PtrReply), MIN(sz, data->ReplySize)); mps_lock(sc); + if (err != 0) + mps_dprint(sc, MPS_FAULT, "%s: failed to copy " + "IOCTL data to user space\n", __func__); - if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || - (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + if (err == 0 && + (function == MPI2_FUNCTION_SCSI_IO_REQUEST || + function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { sense_len = @@ -1024,9 +1031,13 @@ SenseCount)), sizeof(struct scsi_sense_data)); mps_unlock(sc); - copyout(cm->cm_sense, (PTRIN(data->PtrReply + + err = copyout(cm->cm_sense, (PTRIN(data->PtrReply + sizeof(MPI2_SCSI_IO_REPLY))), sense_len); mps_lock(sc); + if (err != 0) + mps_dprint(sc, MPS_FAULT, + "%s: failed to copy IOCTL data to " + "user space\n", __func__); } } } diff --git a/sys/dev/ocs_fc/ocs_ioctl.c b/sys/dev/ocs_fc/ocs_ioctl.c --- a/sys/dev/ocs_fc/ocs_ioctl.c +++ b/sys/dev/ocs_fc/ocs_ioctl.c @@ -86,6 +86,7 @@ ocs_process_sli_config (ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd, ocs_dma_t *dma) { sli4_cmd_sli_config_t *sli_config = (sli4_cmd_sli_config_t *)mcmd->payload; + int error; if (sli_config->emb) { sli4_req_hdr_t *req = (sli4_req_hdr_t *)sli_config->payload.embed; @@ -127,7 +128,13 @@ wrobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys); /* copy the data into the DMA buffer */ - copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes); + error = copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes); + if (error != 0) { + device_printf(ocs->dev, "%s: COMMON_WRITE_OBJECT - copyin failed: %d\n", + __func__, error); + ocs_dma_free(ocs, dma); + return error; + } } break; case SLI4_OPC_COMMON_DELETE_OBJECT: @@ -170,7 +177,13 @@ return ENXIO; } - copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes); + error = copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes); + if (error != 0) { + device_printf(ocs->dev, "%s: non-embedded - copyin failed: %d\n", + __func__, error); + ocs_dma_free(ocs, dma); + return error; + } sli_config->payload.mem.address_low = ocs_addr32_lo(dma->phys); sli_config->payload.mem.address_high = ocs_addr32_hi(dma->phys); @@ -184,6 +197,9 @@ ocs_process_mbx_ioctl(ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd) { ocs_dma_t dma = { 0 }; + int error; + + error = 0; if ((ELXU_BSD_MAGIC != mcmd->magic) || (sizeof(ocs_ioctl_elxu_mbox_t) != mcmd->size)) { @@ -238,13 +254,13 @@ if( SLI4_MBOX_COMMAND_SLI_CONFIG == ((sli4_mbox_command_header_t *)mcmd->payload)->command && mcmd->out_bytes && dma.virt) { - copyout(dma.virt, (void *)(uintptr_t)mcmd->out_addr, mcmd->out_bytes); + error = copyout(dma.virt, (void *)(uintptr_t)mcmd->out_addr, mcmd->out_bytes); } no_support: ocs_dma_free(ocs, &dma); - return 0; + return error; } /** diff --git a/sys/dev/rl/if_rlreg.h b/sys/dev/rl/if_rlreg.h --- a/sys/dev/rl/if_rlreg.h +++ b/sys/dev/rl/if_rlreg.h @@ -545,7 +545,7 @@ /* * The RealTek doesn't use a fragment-based descriptor mechanism. - * Instead, there are only four register sets, each or which represents + * Instead, there are only four register sets, each of which represents * one 'descriptor.' Basically, each TX descriptor is just a contiguous * packet buffer (32-bit aligned!) and we place the buffer addresses in * the registers so the chip knows where they are. diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -634,9 +634,10 @@ return (EINVAL); } if (id != 0) - copyin(ugd->ugd_data, &id, 1); - error = uhid_get_report(sc, ugd->ugd_report_type, id, - NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); + error = copyin(ugd->ugd_data, &id, 1); + if (error == 0) + error = uhid_get_report(sc, ugd->ugd_report_type, id, + NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); break; case USB_SET_REPORT: @@ -661,9 +662,10 @@ return (EINVAL); } if (id != 0) - copyin(ugd->ugd_data, &id, 1); - error = uhid_set_report(sc, ugd->ugd_report_type, id, - NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); + error = copyin(ugd->ugd_data, &id, 1); + if (error == 0) + error = uhid_set_report(sc, ugd->ugd_report_type, id, + NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); break; case USB_GET_REPORT_ID: diff --git a/sys/dev/usb/input/uhid_snes.c b/sys/dev/usb/input/uhid_snes.c --- a/sys/dev/usb/input/uhid_snes.c +++ b/sys/dev/usb/input/uhid_snes.c @@ -359,9 +359,10 @@ return (EINVAL); } if (id != 0) - copyin(ugd->ugd_data, &id, 1); - error = uhid_get_report(sc, ugd->ugd_report_type, id, - NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); + error = copyin(ugd->ugd_data, &id, 1); + if (error == 0) + error = uhid_get_report(sc, ugd->ugd_report_type, id, + NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); break; case USB_SET_REPORT: @@ -386,9 +387,10 @@ return (EINVAL); } if (id != 0) - copyin(ugd->ugd_data, &id, 1); - error = uhid_set_report(sc, ugd->ugd_report_type, id, - NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); + error = copyin(ugd->ugd_data, &id, 1); + if (error == 0) + error = uhid_set_report(sc, ugd->ugd_report_type, id, + NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); break; case USB_GET_REPORT_ID: diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c --- a/sys/dev/virtio/network/if_vtnet.c +++ b/sys/dev/virtio/network/if_vtnet.c @@ -1532,8 +1532,8 @@ m_freem(m_head); return (NULL); } - m->m_len = size; + m_adj(m, ETHER_ALIGN); if (m_head != NULL) { m_tail->m_next = m; m_tail = m; diff --git a/sys/dev/xen/gntdev/gntdev.c b/sys/dev/xen/gntdev/gntdev.c --- a/sys/dev/xen/gntdev/gntdev.c +++ b/sys/dev/xen/gntdev/gntdev.c @@ -383,6 +383,13 @@ } } + /* Copy the output values. */ + arg->index = file_offset; + for (i = 0; error == 0 && i < arg->count; i++) { + if (suword32(&arg->gref_ids[i], grefs[i].gref_id) != 0) + error = EFAULT; + } + if (error != 0) { /* * If target domain maps the gref (by guessing the gref-id), @@ -401,11 +408,6 @@ return (error); } - /* Copy the output values. */ - arg->index = file_offset; - for (i = 0; i < arg->count; i++) - suword32(&arg->gref_ids[i], grefs[i].gref_id); - /* Modify the per user private data. */ mtx_lock(&priv_user->user_data_lock); for (i = 0; i < arg->count; i++) diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -679,17 +679,13 @@ ("len %d, corrupted mbuf?", len)); } xfer = (left > len) ? len : left; -#ifdef notdef - /* Not Yet.. */ - if (uiop->uio_iov->iov_op != NULL) - (*(uiop->uio_iov->iov_op)) - (mbufcp, uiocp, xfer); - else -#endif if (uiop->uio_segflg == UIO_SYSSPACE) NFSBCOPY(mbufcp, uiocp, xfer); - else - copyout(mbufcp, uiocp, xfer); + else { + error = copyout(mbufcp, uiocp, xfer); + if (error != 0) + goto out; + } left -= xfer; len -= xfer; mbufcp += xfer; diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -616,8 +616,10 @@ } } if (sbuf_done(req->serror)) { - copyout(sbuf_data(req->serror), req->error, + nerror = copyout(sbuf_data(req->serror), req->error, imin(req->lerror, sbuf_len(req->serror) + 1)); + if (nerror != 0 && req->nerror == 0) + req->nerror = nerror; } nerror = req->nerror; diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -486,7 +486,7 @@ * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ -void +int cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { @@ -510,11 +510,14 @@ td->td_frame->tf_eip = (int)entry; /* Return address sentinel value to stop stack unwinding. */ - suword((void *)td->td_frame->tf_esp, 0); + if (suword((void *)td->td_frame->tf_esp, 0) != 0) + return (EFAULT); /* Pass the argument to the entry point. */ - suword((void *)(td->td_frame->tf_esp + sizeof(void *)), - (int)arg); + if (suword((void *)(td->td_frame->tf_esp + sizeof(void *)), + (int)arg) != 0) + return (EFAULT); + return (0); } int diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -126,11 +126,14 @@ argv = base; envp = base + (imgp->args->argc + 1); base--; - suword(base, (intptr_t)envp); + if (suword(base, (intptr_t)envp) != 0) + return (EFAULT); base--; - suword(base, (intptr_t)argv); + if (suword(base, (intptr_t)argv) != 0) + return (EFAULT); base--; - suword(base, imgp->args->argc); + if (suword(base, imgp->args->argc) != 0) + return (EFAULT); *stack_base = (uintptr_t)base; return (0); } diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -2146,7 +2146,7 @@ optuio->uio_iov[errmsg_pos].iov_base, errmsg_len); else - copyout(errmsg, + (void)copyout(errmsg, optuio->uio_iov[errmsg_pos].iov_base, errmsg_len); } @@ -2580,7 +2580,7 @@ optuio->uio_iov[errmsg_pos].iov_base, errmsg_len); else - copyout(errmsg, + (void)copyout(errmsg, optuio->uio_iov[errmsg_pos].iov_base, errmsg_len); } diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c --- a/sys/kern/kern_sendfile.c +++ b/sys/kern/kern_sendfile.c @@ -1328,7 +1328,7 @@ fdrop(fp, td); if (uap->sbytes != NULL) - copyout(&sbytes, uap->sbytes, sizeof(off_t)); + (void)copyout(&sbytes, uap->sbytes, sizeof(off_t)); out: free(hdr_uio, M_IOV); diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -146,6 +146,7 @@ { stack_t stack; struct thr_param *param; + int error; /* * Here we copy out tid to two places, one for child and one @@ -165,7 +166,9 @@ stack.ss_sp = param->stack_base; stack.ss_size = param->stack_size; /* Set upcall address to user thread entry function. */ - cpu_set_upcall(td, param->start_func, param->arg, &stack); + error = cpu_set_upcall(td, param->start_func, param->arg, &stack); + if (error != 0) + return (error); /* Setup user TLS address and TLS pointer register. */ return (cpu_set_user_tls(td, param->tls_base)); } @@ -312,8 +315,8 @@ /* Signal userland that it can free the stack. */ if ((void *)uap->state != NULL) { - suword_lwpid(uap->state, 1); - kern_umtx_wake(td, uap->state, INT_MAX, 0); + (void)suword_lwpid(uap->state, 1); + (void)kern_umtx_wake(td, uap->state, INT_MAX, 0); } return (kern_thr_exit(td)); diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -2960,7 +2960,14 @@ */ error = fueword32(&cv->c_has_waiters, &hasw); if (error == 0 && hasw == 0) - suword32(&cv->c_has_waiters, 1); + error = suword32(&cv->c_has_waiters, 1); + if (error != 0) { + umtxq_lock(&uq->uq_key); + umtxq_remove(uq); + umtxq_unbusy(&uq->uq_key); + error = EFAULT; + goto out; + } umtxq_unbusy_unlocked(&uq->uq_key); @@ -2990,7 +2997,9 @@ umtxq_remove(uq); if (oldlen == 1) { umtxq_unlock(&uq->uq_key); - suword32(&cv->c_has_waiters, 0); + if (suword32(&cv->c_has_waiters, 0) != 0 && + error == 0) + error = EFAULT; umtxq_lock(&uq->uq_key); } } @@ -2998,7 +3007,7 @@ if (error == ERESTART) error = EINTR; } - +out: umtxq_unlock(&uq->uq_key); umtx_key_release(&uq->uq_key); return (error); @@ -3176,12 +3185,14 @@ */ rv = fueword32(&rwlock->rw_blocked_readers, &blocked_readers); + if (rv == 0) + rv = suword32(&rwlock->rw_blocked_readers, + blocked_readers + 1); if (rv == -1) { umtxq_unbusy_unlocked(&uq->uq_key); error = EFAULT; break; } - suword32(&rwlock->rw_blocked_readers, blocked_readers+1); while (state & wrflags) { umtxq_lock(&uq->uq_key); @@ -3206,12 +3217,14 @@ /* decrease read waiter count, and may clear read contention bit */ rv = fueword32(&rwlock->rw_blocked_readers, &blocked_readers); + if (rv == 0) + rv = suword32(&rwlock->rw_blocked_readers, + blocked_readers - 1); if (rv == -1) { umtxq_unbusy_unlocked(&uq->uq_key); error = EFAULT; break; } - suword32(&rwlock->rw_blocked_readers, blocked_readers-1); if (blocked_readers == 1) { rv = fueword32(&rwlock->rw_state, &state); if (rv == -1) { @@ -3360,12 +3373,14 @@ sleep: rv = fueword32(&rwlock->rw_blocked_writers, &blocked_writers); + if (rv == 0) + rv = suword32(&rwlock->rw_blocked_writers, + blocked_writers + 1); if (rv == -1) { umtxq_unbusy_unlocked(&uq->uq_key); error = EFAULT; break; } - suword32(&rwlock->rw_blocked_writers, blocked_writers + 1); while ((state & URWLOCK_WRITE_OWNER) || URWLOCK_READER_COUNT(state) != 0) { @@ -3390,12 +3405,14 @@ rv = fueword32(&rwlock->rw_blocked_writers, &blocked_writers); + if (rv == 0) + rv = suword32(&rwlock->rw_blocked_writers, + blocked_writers - 1); if (rv == -1) { umtxq_unbusy_unlocked(&uq->uq_key); error = EFAULT; break; } - suword32(&rwlock->rw_blocked_writers, blocked_writers-1); if (blocked_writers == 1) { rv = fueword32(&rwlock->rw_state, &state); if (rv == -1) { @@ -3574,7 +3591,7 @@ rv1 = fueword32(&sem->_count, &count); if (rv == -1 || rv1 == -1 || count != 0 || (rv == 1 && count1 == 0)) { if (rv == 0) - suword32(&sem->_has_waiters, 0); + rv = suword32(&sem->_has_waiters, 0); umtxq_lock(&uq->uq_key); umtxq_unbusy(&uq->uq_key); umtxq_remove(uq); diff --git a/sys/kern/kern_xxx.c b/sys/kern/kern_xxx.c --- a/sys/kern/kern_xxx.c +++ b/sys/kern/kern_xxx.c @@ -324,7 +324,9 @@ 1, 0, 0, 0, 0); if (error) return (error); - subyte( uap->name->sysname + sizeof(uap->name->sysname) - 1, 0); + error = subyte(uap->name->sysname + sizeof(uap->name->sysname) - 1, 0); + if (error) + return (EFAULT); name[1] = KERN_HOSTNAME; len = sizeof uap->name->nodename; @@ -332,7 +334,9 @@ 1, 0, 0, 0, 0); if (error) return (error); - subyte( uap->name->nodename + sizeof(uap->name->nodename) - 1, 0); + error = subyte(uap->name->nodename + sizeof(uap->name->nodename) - 1, 0); + if (error) + return (EFAULT); name[1] = KERN_OSRELEASE; len = sizeof uap->name->release; @@ -340,7 +344,9 @@ 1, 0, 0, 0, 0); if (error) return (error); - subyte( uap->name->release + sizeof(uap->name->release) - 1, 0); + error = subyte(uap->name->release + sizeof(uap->name->release) - 1, 0); + if (error) + return (EFAULT); /* name = KERN_VERSION; @@ -358,13 +364,11 @@ for(s = version; *s && *s != '#'; s++); for(us = uap->name->version; *s && *s != ':'; s++) { - error = subyte( us++, *s); - if (error) - return (error); + if (subyte(us++, *s) != 0) + return (EFAULT); } - error = subyte( us++, 0); - if (error) - return (error); + if (subyte(us++, 0) != 0) + return (EFAULT); name[0] = CTL_HW; name[1] = HW_MACHINE; @@ -373,7 +377,9 @@ 1, 0, 0, 0, 0); if (error) return (error); - subyte( uap->name->machine + sizeof(uap->name->machine) - 1, 0); + error = subyte(uap->name->machine + sizeof(uap->name->machine) - 1, 0); + if (error) + return (EFAULT); return (0); } diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c --- a/sys/kern/uipc_ktls.c +++ b/sys/kern/uipc_ktls.c @@ -3160,8 +3160,9 @@ * backlogs of buffers to be encrypted, leading to * surges of traffic and potential NIC output drops. */ - if (!vm_page_reclaim_contig_domain_ext(domain, VM_ALLOC_NORMAL, - atop(ktls_maxlen), 0, ~0ul, PAGE_SIZE, 0, ktls_max_reclaim)) { + if (vm_page_reclaim_contig_domain_ext(domain, VM_ALLOC_NORMAL, + atop(ktls_maxlen), 0, ~0ul, PAGE_SIZE, 0, + ktls_max_reclaim) != 0) { vm_wait_domain(domain); } else { sc->reclaims += ktls_max_reclaim; diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -877,8 +877,9 @@ } error = vm_page_reclaim_contig(aflags, pagesizes[psind] / PAGE_SIZE, 0, ~0, - pagesizes[psind], 0) ? 0 : - vm_wait_intr(object); + pagesizes[psind], 0); + if (error == ENOMEM) + error = vm_wait_intr(object); if (error != 0) { VM_OBJECT_WLOCK(object); return (error); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1024,7 +1024,7 @@ fsoptions->uio_iov[2 * errmsg_pos + 1].iov_base, fsoptions->uio_iov[2 * errmsg_pos + 1].iov_len); } else { - copyout(errmsg, + (void)copyout(errmsg, fsoptions->uio_iov[2 * errmsg_pos + 1].iov_base, fsoptions->uio_iov[2 * errmsg_pos + 1].iov_len); } @@ -1388,7 +1388,7 @@ error = EINVAL; goto end; } - if (fsidcmp(&fsid_up, &mp->mnt_stat.f_fsid) != 0) { + if (fsidcmp(fsid_up, &mp->mnt_stat.f_fsid) != 0) { error = ENOENT; goto end; } diff --git a/sys/net/pfil.c b/sys/net/pfil.c --- a/sys/net/pfil.c +++ b/sys/net/pfil.c @@ -295,6 +295,7 @@ free(link, M_PFIL); } PFIL_UNLOCK(); + free(ph, M_PFIL); } pfil_hook_t diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h --- a/sys/net80211/ieee80211.h +++ b/sys/net80211/ieee80211.h @@ -869,29 +869,25 @@ struct ieee80211_vht_mcs_info supp_mcs; } __packed; -/* VHT capabilities element: 802.11ac-2013 8.4.2.160 */ -struct ieee80211_ie_vhtcap { - uint8_t ie; - uint8_t len; - uint32_t vht_cap_info; - struct ieee80211_vht_mcs_info supp_mcs; -} __packed; - -/* VHT operation mode subfields - 802.11ac-2013 Table 8.183x */ -#define IEEE80211_VHT_CHANWIDTH_USE_HT 0 /* Use HT IE for chw */ -#define IEEE80211_VHT_CHANWIDTH_80MHZ 1 /* 80MHz */ -#define IEEE80211_VHT_CHANWIDTH_160MHZ 2 /* 160MHz */ -#define IEEE80211_VHT_CHANWIDTH_80P80MHZ 3 /* 80+80MHz */ +/* 802.11ac-2013, Table 8-183x-VHT Operation Information subfields */ +enum ieee80211_vht_chanwidth { + IEEE80211_VHT_CHANWIDTH_USE_HT = 0, /* 20 MHz or 40 MHz */ + IEEE80211_VHT_CHANWIDTH_80MHZ = 1, /* 80MHz */ + IEEE80211_VHT_CHANWIDTH_160MHZ = 2, /* 160MHz */ + IEEE80211_VHT_CHANWIDTH_80P80MHZ = 3, /* 80+80MHz */ + /* 4..255 reserved. */ +}; -/* VHT operation IE - 802.11ac-2013 8.4.2.161 */ -struct ieee80211_ie_vht_operation { - uint8_t ie; - uint8_t len; - uint8_t chan_width; - uint8_t center_freq_seg1_idx; - uint8_t center_freq_seg2_idx; - uint16_t basic_mcs_set; +/* The name conflicts with the same structure in wpa. Only ifconfig needs this. */ +#if defined(_KERNEL) || defined(WANT_NET80211) +/* 802.11ac-2013 8.4.2.161 VHT Operation element */ +struct ieee80211_vht_operation { + uint8_t chan_width; /* enum ieee80211_vht_chanwidth */ + uint8_t center_freq_seq0_idx; /* 20/40/80/160 - VHT chan1 */ + uint8_t center_freq_seq1_idx; /* 80+80 - VHT chan2 */ + uint16_t basic_mcs_set; /* Basic VHT-MCS and NSS Set */ } __packed; +#endif /* 802.11ac VHT Capabilities */ #define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895 0x00000000 diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -2125,12 +2125,12 @@ /* Validate VHT IEs */ if (vhtcap != NULL) { IEEE80211_VERIFY_LENGTH(vhtcap[1], - sizeof(struct ieee80211_ie_vhtcap) - 2, + sizeof(struct ieee80211_vht_cap), return); } if (vhtinfo != NULL) { IEEE80211_VERIFY_LENGTH(vhtinfo[1], - sizeof(struct ieee80211_ie_vht_operation) - 2, + sizeof(struct ieee80211_vht_operation), return); } diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -773,12 +773,12 @@ /* Process VHT IEs */ if (scan->vhtcap != NULL) { IEEE80211_VERIFY_LENGTH(scan->vhtcap[1], - sizeof(struct ieee80211_ie_vhtcap) - 2, + sizeof(struct ieee80211_vht_cap), scan->vhtcap = NULL); } if (scan->vhtopmode != NULL) { IEEE80211_VERIFY_LENGTH(scan->vhtopmode[1], - sizeof(struct ieee80211_ie_vht_operation) - 2, + sizeof(struct ieee80211_vht_operation), scan->vhtopmode = NULL); } diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -2456,7 +2456,7 @@ sizeof(struct ieee80211_ie_htcap) : 0) #ifdef notyet + sizeof(struct ieee80211_ie_htinfo) /* XXX not needed? */ - + sizeof(struct ieee80211_ie_vhtcap) + + 2 + sizeof(struct ieee80211_vht_cap) #endif + ((vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) ? vap->iv_wpa_ie[1] : 0) @@ -2821,7 +2821,7 @@ + 2 + 26 + sizeof(struct ieee80211_wme_info) + sizeof(struct ieee80211_ie_htcap) - + sizeof(struct ieee80211_ie_vhtcap) + + 2 + sizeof(struct ieee80211_vht_cap) + 4 + sizeof(struct ieee80211_ie_htcap) #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) @@ -2954,8 +2954,8 @@ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + sizeof(struct ieee80211_ie_htcap) + 4 + sizeof(struct ieee80211_ie_htinfo) + 4 - + sizeof(struct ieee80211_ie_vhtcap) - + sizeof(struct ieee80211_ie_vht_operation) + + 2 + sizeof(struct ieee80211_vht_cap) + + 2 + sizeof(struct ieee80211_vht_operation) + sizeof(struct ieee80211_wme_param) #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) @@ -3113,8 +3113,8 @@ + sizeof(struct ieee80211_wme_param) + 4 + sizeof(struct ieee80211_ie_htcap) + 4 + sizeof(struct ieee80211_ie_htinfo) - + sizeof(struct ieee80211_ie_vhtcap) - + sizeof(struct ieee80211_ie_vht_operation) + + 2 + sizeof(struct ieee80211_vht_cap) + + 2 + sizeof(struct ieee80211_vht_operation) #ifdef IEEE80211_SUPPORT_SUPERG + sizeof(struct ieee80211_ath_ie) #endif @@ -3728,8 +3728,8 @@ /* XXX conditional? */ + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ - + sizeof(struct ieee80211_ie_vhtcap)/* VHT caps */ - + sizeof(struct ieee80211_ie_vht_operation)/* VHT info */ + + 2 + sizeof(struct ieee80211_vht_cap)/* VHT caps */ + + 2 + sizeof(struct ieee80211_vht_operation)/* VHT info */ + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ sizeof(struct ieee80211_wme_param) : 0) #ifdef IEEE80211_SUPPORT_SUPERG diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -2506,6 +2506,13 @@ nstate = vap->iv_nstate; arg = vap->iv_nstate_arg; + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, + "%s:%d: running state update %s -> %s (%d)\n", + __func__, __LINE__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[vap->iv_nstate], + npending); + if (vap->iv_flags_ext & IEEE80211_FEXT_REINIT) { /* * We have been requested to drop back to the INIT before @@ -2673,29 +2680,30 @@ * until this is completed. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, - "%s: %s -> %s (%s) transition discarded\n", - __func__, + "%s:%d: %s -> %s (%s) transition discarded\n", + __func__, __LINE__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate], ieee80211_state_name[vap->iv_nstate]); return -1; } else if (vap->iv_state != vap->iv_nstate) { -#if 0 /* Warn if the previous state hasn't completed. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, - "%s: pending %s -> %s transition lost\n", __func__, + "%s:%d: pending %s -> %s (now to %s) transition lost\n", + __func__, __LINE__, ieee80211_state_name[vap->iv_state], - ieee80211_state_name[vap->iv_nstate]); -#else - /* XXX temporarily enable to identify issues */ - if_printf(vap->iv_ifp, - "%s: pending %s -> %s transition lost\n", - __func__, ieee80211_state_name[vap->iv_state], - ieee80211_state_name[vap->iv_nstate]); -#endif + ieee80211_state_name[vap->iv_nstate], + ieee80211_state_name[nstate]); } } + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, + "%s:%d: starting state update %s -> %s (%s)\n", + __func__, __LINE__, + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[vap->iv_nstate], + ieee80211_state_name[nstate]); + nrunning = nscanning = 0; /* XXX can track this state instead of calculating */ TAILQ_FOREACH(vp, &ic->ic_vaps, iv_next) { diff --git a/sys/net80211/ieee80211_vht.h b/sys/net80211/ieee80211_vht.h --- a/sys/net80211/ieee80211_vht.h +++ b/sys/net80211/ieee80211_vht.h @@ -61,8 +61,8 @@ struct ieee80211_channel *, int); void ieee80211_vht_get_vhtcap_ie(struct ieee80211_node *ni, - struct ieee80211_ie_vhtcap *, int); + struct ieee80211_vht_cap *, int); void ieee80211_vht_get_vhtinfo_ie(struct ieee80211_node *ni, - struct ieee80211_ie_vht_operation *, int); + struct ieee80211_vht_operation *, int); #endif /* _NET80211_IEEE80211_VHT_H_ */ diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c --- a/sys/net80211/ieee80211_vht.c +++ b/sys/net80211/ieee80211_vht.c @@ -338,7 +338,7 @@ */ void ieee80211_vht_get_vhtcap_ie(struct ieee80211_node *ni, - struct ieee80211_ie_vhtcap *vhtcap, int opmode) + struct ieee80211_vht_cap *vhtcap, int opmode) { struct ieee80211vap *vap = ni->ni_vap; // struct ieee80211com *ic = vap->iv_ic; @@ -346,9 +346,6 @@ uint32_t new_vhtcap; int i; - vhtcap->ie = IEEE80211_ELEMID_VHT_CAP; - vhtcap->len = sizeof(struct ieee80211_ie_vhtcap) - 2; - /* * Capabilities - it depends on whether we are a station * or not. @@ -676,19 +673,12 @@ uint8_t * ieee80211_add_vhtcap(uint8_t *frm, struct ieee80211_node *ni) { - struct ieee80211_ie_vhtcap vhtcap; - int opmode; - - opmode = 0; - if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) - opmode = 1; - - ieee80211_vht_get_vhtcap_ie(ni, &vhtcap, opmode); + struct ieee80211_vht_cap vhtcap; - memset(frm, '\0', sizeof(struct ieee80211_ie_vhtcap)); + ieee80211_vht_get_vhtcap_ie(ni, &vhtcap, 1); frm[0] = IEEE80211_ELEMID_VHT_CAP; - frm[1] = sizeof(struct ieee80211_ie_vhtcap) - 2; + frm[1] = sizeof(vhtcap); frm += 2; /* 32-bit VHT capability */ @@ -771,10 +761,9 @@ uint8_t * ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *ni) { - memset(frm, '\0', sizeof(struct ieee80211_ie_vht_operation)); frm[0] = IEEE80211_ELEMID_VHT_OPMODE; - frm[1] = sizeof(struct ieee80211_ie_vht_operation) - 2; + frm[1] = sizeof(struct ieee80211_vht_operation); frm += 2; /* 8-bit chanwidth */ @@ -882,7 +871,7 @@ */ void ieee80211_vht_get_vhtinfo_ie(struct ieee80211_node *ni, - struct ieee80211_ie_vht_operation *vhtop, int opmode) + struct ieee80211_vht_operation *vhtop, int opmode) { printf("%s: called; TODO!\n", __func__); } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1576,6 +1576,7 @@ th->th_win = htons(th->th_win); th->th_urp = htons(th->th_urp); } +#endif /* _KERNEL */ static inline uint16_t tcp_get_flags(const struct tcphdr *th) @@ -1589,6 +1590,4 @@ th->th_x2 = (flags >> 8) & 0x0f; th->th_flags = flags & 0xff; } -#endif /* _KERNEL */ - #endif /* _NETINET_TCP_VAR_H_ */ diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -100,6 +100,13 @@ PF_ST_VERSION = 28, /* u64 */ PF_ST_FILTER_ADDR = 29, /* in6_addr */ PF_ST_FILTER_MASK = 30, /* in6_addr */ + PF_ST_RTABLEID = 31, /* i32 */ + PF_ST_MIN_TTL = 32, /* u8 */ + PF_ST_MAX_MSS = 33, /* u16 */ + PF_ST_DNPIPE = 34, /* u16 */ + PF_ST_DNRPIPE = 35, /* u16 */ + PF_ST_RT = 36, /* u8 */ + PF_ST_RT_IFNAME = 37, /* string */ }; enum pf_addr_type_t { diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,14 @@ nlattr_add_u64(nw, PF_ST_PACKETS1, s->packets[1]); nlattr_add_u64(nw, PF_ST_BYTES0, s->bytes[0]); nlattr_add_u64(nw, PF_ST_BYTES1, s->bytes[1]); + nlattr_add_u32(nw, PF_ST_RTABLEID, s->act.rtableid); + nlattr_add_u8(nw, PF_ST_MIN_TTL, s->act.min_ttl); + nlattr_add_u16(nw, PF_ST_MAX_MSS, s->act.max_mss); + nlattr_add_u16(nw, PF_ST_DNPIPE, s->act.dnpipe); + nlattr_add_u16(nw, PF_ST_DNRPIPE, s->act.dnrpipe); + nlattr_add_u8(nw, PF_ST_RT, s->rt); + if (s->rt_kif != NULL) + nlattr_add_string(nw, PF_ST_RT_IFNAME, s->rt_kif->pfik_name); if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src)) goto enomem; @@ -704,36 +713,42 @@ .cmd_name = "GETSTATES", .cmd_cb = pf_handle_getstates, .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, }, { .cmd_num = PFNL_CMD_GETCREATORS, .cmd_name = "GETCREATORS", .cmd_cb = pf_handle_getcreators, .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, }, { .cmd_num = PFNL_CMD_START, .cmd_name = "START", .cmd_cb = pf_handle_start, .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, }, { .cmd_num = PFNL_CMD_STOP, .cmd_name = "STOP", .cmd_cb = pf_handle_stop, .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, }, { .cmd_num = PFNL_CMD_ADDRULE, .cmd_name = "ADDRULE", .cmd_cb = pf_handle_addrule, .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, }, { .cmd_num = PFNL_CMD_GETRULES, .cmd_name = "GETRULES", .cmd_cb = pf_handle_getrules, .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, }, }; diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c --- a/sys/powerpc/powerpc/exec_machdep.c +++ b/sys/powerpc/powerpc/exec_machdep.c @@ -1149,12 +1149,15 @@ td->td_md.md_saved_msr = psl_kernset; } -void +int cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { struct trapframe *tf; uintptr_t sp; + #ifdef __powerpc64__ + int error; + #endif tf = td->td_frame; /* align stack and alloc space for frame ptr and saved LR */ @@ -1182,10 +1185,12 @@ tf->srr0 = (register_t)entry; /* ELFv2 ABI requires that the global entry point be in r12. */ tf->fixreg[12] = (register_t)entry; - } - else { + } else { register_t entry_desc[3]; - (void)copyin((void *)entry, entry_desc, sizeof(entry_desc)); + error = copyin((void *)entry, entry_desc, + sizeof(entry_desc)); + if (error != 0) + return (error); tf->srr0 = entry_desc[0]; tf->fixreg[2] = entry_desc[1]; tf->fixreg[11] = entry_desc[2]; @@ -1201,6 +1206,7 @@ td->td_retval[0] = (register_t)entry; td->td_retval[1] = 0; + return (0); } static int diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -178,7 +178,7 @@ * Set that machine state for performing an upcall that starts * the entry function with the given argument. */ -void +int cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { @@ -189,6 +189,7 @@ tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size); tf->tf_sepc = (register_t)entry; tf->tf_a[0] = (register_t)arg; + return (0); } int diff --git a/sys/sys/param.h b/sys/sys/param.h --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -73,7 +73,7 @@ * cannot include sys/param.h and should only be updated here. */ #undef __FreeBSD_version -#define __FreeBSD_version 1500007 +#define __FreeBSD_version 1500008 /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/proc.h b/sys/sys/proc.h --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1257,7 +1257,7 @@ int cpu_procctl(struct thread *td, int idtype, id_t id, int com, void *data); void cpu_set_syscall_retval(struct thread *, int); -void cpu_set_upcall(struct thread *, void (*)(void *), void *, +int cpu_set_upcall(struct thread *, void (*)(void *), void *, stack_t *); int cpu_set_user_tls(struct thread *, void *tls_base); void cpu_thread_alloc(struct thread *); diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -2417,8 +2417,10 @@ if (uio->uio_offset < 0) return (EINVAL); ip = VTOI(vp); - if (ip->i_effnlink == 0) + if (ip->i_effnlink == 0) { + *ap->a_eofflag = 1; return (0); + } if (ap->a_ncookies != NULL) { if (uio->uio_resid < 0) ncookies = 0; diff --git a/sys/vm/vm_domainset.h b/sys/vm/vm_domainset.h --- a/sys/vm/vm_domainset.h +++ b/sys/vm/vm_domainset.h @@ -31,6 +31,7 @@ struct vm_domainset_iter { struct domainset *di_domain; unsigned int *di_iter; + domainset_t di_valid_mask; vm_pindex_t di_offset; int di_flags; uint16_t di_policy; @@ -47,6 +48,7 @@ struct domainset *, int *, int *); void vm_domainset_iter_policy_ref_init(struct vm_domainset_iter *, struct domainset_ref *, int *, int *); +void vm_domainset_iter_ignore(struct vm_domainset_iter *, int); int vm_wait_doms(const domainset_t *, int mflags); diff --git a/sys/vm/vm_domainset.c b/sys/vm/vm_domainset.c --- a/sys/vm/vm_domainset.c +++ b/sys/vm/vm_domainset.c @@ -68,6 +68,7 @@ di->di_domain = ds; di->di_iter = iter; di->di_policy = ds->ds_policy; + DOMAINSET_COPY(&ds->ds_mask, &di->di_valid_mask); if (di->di_policy == DOMAINSET_POLICY_INTERLEAVE) { #if VM_NRESERVLEVEL > 0 if (vm_object_reserv(obj)) { @@ -158,7 +159,7 @@ switch (di->di_policy) { case DOMAINSET_POLICY_FIRSTTOUCH: *domain = PCPU_GET(domain); - if (DOMAINSET_ISSET(*domain, &di->di_domain->ds_mask)) { + if (DOMAINSET_ISSET(*domain, &di->di_valid_mask)) { /* * Add an extra iteration because we will visit the * current domain a second time in the rr iterator. @@ -221,11 +222,14 @@ vm_domainset_iter_page(struct vm_domainset_iter *di, struct vm_object *obj, int *domain) { + if (__predict_false(DOMAINSET_EMPTY(&di->di_valid_mask))) + return (ENOMEM); /* If there are more domains to visit we run the iterator. */ while (--di->di_n != 0) { vm_domainset_iter_next(di, domain); - if (!di->di_minskip || !vm_page_count_min_domain(*domain)) + if (DOMAINSET_ISSET(*domain, &di->di_valid_mask) && + (!di->di_minskip || !vm_page_count_min_domain(*domain))) return (0); } @@ -243,7 +247,7 @@ /* Wait for one of the domains to accumulate some free pages. */ if (obj != NULL) VM_OBJECT_WUNLOCK(obj); - vm_wait_doms(&di->di_domain->ds_mask, 0); + vm_wait_doms(&di->di_valid_mask, 0); if (obj != NULL) VM_OBJECT_WLOCK(obj); if ((di->di_flags & VM_ALLOC_WAITFAIL) != 0) @@ -288,11 +292,14 @@ int vm_domainset_iter_policy(struct vm_domainset_iter *di, int *domain) { + if (DOMAINSET_EMPTY(&di->di_valid_mask)) + return (ENOMEM); /* If there are more domains to visit we run the iterator. */ while (--di->di_n != 0) { vm_domainset_iter_next(di, domain); - if (!di->di_minskip || !vm_page_count_min_domain(*domain)) + if (DOMAINSET_ISSET(*domain, &di->di_valid_mask) && + (!di->di_minskip || !vm_page_count_min_domain(*domain))) return (0); } @@ -308,7 +315,7 @@ return (ENOMEM); /* Wait for one of the domains to accumulate some free pages. */ - vm_wait_doms(&di->di_domain->ds_mask, 0); + vm_wait_doms(&di->di_valid_mask, 0); /* Restart the search. */ vm_domainset_iter_first(di, domain); @@ -316,6 +323,15 @@ return (0); } +void +vm_domainset_iter_ignore(struct vm_domainset_iter *di, int domain) +{ + KASSERT(DOMAINSET_ISSET(domain, &di->di_valid_mask), + ("%s: domain %d not present in di_valid_mask for di %p", + __func__, domain, di)); + DOMAINSET_CLR(domain, &di->di_valid_mask); +} + #else /* !NUMA */ int @@ -357,4 +373,10 @@ *domain = 0; } +void +vm_domainset_iter_ignore(struct vm_domainset_iter *di __unused, + int domain __unused) +{ +} + #endif /* NUMA */ diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -232,8 +232,8 @@ break; VM_OBJECT_WUNLOCK(object); - if (!vm_page_reclaim_contig_domain(domain, pflags, npages, - low, high, alignment, boundary) && wait) + if (vm_page_reclaim_contig_domain(domain, pflags, npages, + low, high, alignment, boundary) == ENOMEM && wait) vm_wait_domain(domain); VM_OBJECT_WLOCK(object); } @@ -306,8 +306,12 @@ vm_paddr_t low, vm_paddr_t high, vm_memattr_t memattr) { struct vm_domainset_iter di; + vm_page_t bounds[2]; void *addr; int domain; + int start_segind; + + start_segind = -1; vm_domainset_iter_policy_init(&di, ds, &domain, &flags); do { @@ -315,6 +319,12 @@ memattr); if (addr != NULL) break; + if (start_segind == -1) + start_segind = vm_phys_lookup_segind(low); + if (vm_phys_find_range(bounds, start_segind, domain, + atop(round_page(size)), low, high) == -1) { + vm_domainset_iter_ignore(&di, domain); + } } while (vm_domainset_iter_policy(&di, &domain) == 0); return (addr); @@ -390,8 +400,12 @@ vm_memattr_t memattr) { struct vm_domainset_iter di; + vm_page_t bounds[2]; void *addr; int domain; + int start_segind; + + start_segind = -1; vm_domainset_iter_policy_init(&di, ds, &domain, &flags); do { @@ -399,6 +413,12 @@ alignment, boundary, memattr); if (addr != NULL) break; + if (start_segind == -1) + start_segind = vm_phys_lookup_segind(low); + if (vm_phys_find_range(bounds, start_segind, domain, + atop(round_page(size)), low, high) == -1) { + vm_domainset_iter_ignore(&di, domain); + } } while (vm_domainset_iter_policy(&di, &domain) == 0); return (addr); diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -660,11 +660,11 @@ bool vm_page_ps_test(vm_page_t m, int flags, vm_page_t skip_m); void vm_page_putfake(vm_page_t m); void vm_page_readahead_finish(vm_page_t m); -bool vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, +int vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary); -bool vm_page_reclaim_contig_domain(int domain, int req, u_long npages, +int vm_page_reclaim_contig_domain(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary); -bool vm_page_reclaim_contig_domain_ext(int domain, int req, u_long npages, +int vm_page_reclaim_contig_domain_ext(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary, int desired_runs); void vm_page_reference(vm_page_t m); @@ -730,9 +730,9 @@ #define vm_page_assert_unbusied(m) \ KASSERT((vm_page_busy_fetch(m) & ~VPB_BIT_WAITERS) != \ VPB_CURTHREAD_EXCLUSIVE, \ - ("vm_page_assert_xbusied: page %p busy_lock %#x owned" \ - " by me @ %s:%d", \ - (m), (m)->busy_lock, __FILE__, __LINE__)); \ + ("vm_page_assert_unbusied: page %p busy_lock %#x owned" \ + " by me (%p) @ %s:%d", \ + (m), (m)->busy_lock, curthread, __FILE__, __LINE__)); \ #define vm_page_assert_xbusied_unchecked(m) do { \ KASSERT(vm_page_xbusied(m), \ @@ -744,8 +744,8 @@ KASSERT((vm_page_busy_fetch(m) & ~VPB_BIT_WAITERS) == \ VPB_CURTHREAD_EXCLUSIVE, \ ("vm_page_assert_xbusied: page %p busy_lock %#x not owned" \ - " by me @ %s:%d", \ - (m), (m)->busy_lock, __FILE__, __LINE__)); \ + " by me (%p) @ %s:%d", \ + (m), (m)->busy_lock, curthread, __FILE__, __LINE__)); \ } while (0) #define vm_page_busied(m) \ diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -2170,8 +2170,12 @@ vm_paddr_t boundary, vm_memattr_t memattr) { struct vm_domainset_iter di; + vm_page_t bounds[2]; vm_page_t m; int domain; + int start_segind; + + start_segind = -1; vm_domainset_iter_page_init(&di, object, pindex, &domain, &req); do { @@ -2179,6 +2183,12 @@ npages, low, high, alignment, boundary, memattr); if (m != NULL) break; + if (start_segind == -1) + start_segind = vm_phys_lookup_segind(low); + if (vm_phys_find_range(bounds, start_segind, domain, + npages, low, high) == -1) { + vm_domainset_iter_ignore(&di, domain); + } } while (vm_domainset_iter_page(&di, object, &domain) == 0); return (m); @@ -3022,7 +3032,7 @@ * "npages" must be greater than zero. Both "alignment" and "boundary" * must be a power of two. */ -bool +int vm_page_reclaim_contig_domain_ext(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary, int desired_runs) @@ -3030,14 +3040,15 @@ struct vm_domain *vmd; vm_page_t bounds[2], m_run, _m_runs[NRUNS], *m_runs; u_long count, minalign, reclaimed; - int error, i, min_reclaim, nruns, options, req_class, segind; - bool ret; + int error, i, min_reclaim, nruns, options, req_class; + int segind, start_segind; + int ret; KASSERT(npages > 0, ("npages is 0")); KASSERT(powerof2(alignment), ("alignment is not a power of 2")); KASSERT(powerof2(boundary), ("boundary is not a power of 2")); - ret = false; + ret = ENOMEM; /* * If the caller wants to reclaim multiple runs, try to allocate @@ -3077,6 +3088,8 @@ if (curproc == pageproc && req_class != VM_ALLOC_INTERRUPT) req_class = VM_ALLOC_SYSTEM; + start_segind = vm_phys_lookup_segind(low); + /* * Return if the number of free pages cannot satisfy the requested * allocation. @@ -3093,14 +3106,17 @@ * the reclamation of reservations and superpages each time. */ for (options = VPSC_NORESERV;;) { + bool phys_range_exists = false; + /* * Find the highest runs that satisfy the given constraints * and restrictions, and record them in "m_runs". */ count = 0; - segind = vm_phys_lookup_segind(low); + segind = start_segind; while ((segind = vm_phys_find_range(bounds, segind, domain, npages, low, high)) != -1) { + phys_range_exists = true; while ((m_run = vm_page_scan_contig(npages, bounds[0], bounds[1], alignment, boundary, options))) { bounds[0] = m_run + npages; @@ -3110,6 +3126,11 @@ segind++; } + if (!phys_range_exists) { + ret = ERANGE; + goto done; + } + /* * Reclaim the highest runs in LIFO (descending) order until * the number of reclaimed pages, "reclaimed", is at least @@ -3126,7 +3147,7 @@ if (error == 0) { reclaimed += npages; if (reclaimed >= min_reclaim) { - ret = true; + ret = 0; goto done; } } @@ -3141,7 +3162,8 @@ else if (options == VPSC_NOSUPER) options = VPSC_ANY; else if (options == VPSC_ANY) { - ret = reclaimed != 0; + if (reclaimed != 0) + ret = 0; goto done; } } @@ -3151,7 +3173,7 @@ return (ret); } -bool +int vm_page_reclaim_contig_domain(int domain, int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary) { @@ -3159,20 +3181,28 @@ alignment, boundary, 1)); } -bool +int vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary) { struct vm_domainset_iter di; - int domain; - bool ret; + int domain, ret, status; + + ret = ERANGE; vm_domainset_iter_page_init(&di, NULL, 0, &domain, &req); do { - ret = vm_page_reclaim_contig_domain(domain, req, npages, low, + status = vm_page_reclaim_contig_domain(domain, req, npages, low, high, alignment, boundary); - if (ret) - break; + if (status == 0) + return (0); + else if (status == ERANGE) + vm_domainset_iter_ignore(&di, domain); + else { + KASSERT(status == ENOMEM, ("Unrecognized error %d " + "from vm_page_reclaim_contig_domain()", status)); + ret = ENOMEM; + } } while (vm_domainset_iter_page(&di, NULL, &domain) == 0); return (ret); diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c --- a/sys/vm/vm_phys.c +++ b/sys/vm/vm_phys.c @@ -1169,24 +1169,6 @@ vm_freelist_add(fl, m, order, 1); } -/* - * Return the largest possible order of a set of pages starting at m. - */ -static int -max_order(vm_page_t m) -{ - - /* - * Unsigned "min" is used here so that "order" is assigned - * "VM_NFREEORDER - 1" when "m"'s physical address is zero - * or the low-order bits of its physical address are zero - * because the size of a physical address exceeds the size of - * a long. - */ - return (min(ffsll(VM_PAGE_TO_PHYS(m) >> PAGE_SHIFT) - 1, - VM_NFREEORDER - 1)); -} - /* * Free a contiguous, arbitrarily sized set of physical pages, without * merging across set boundaries. @@ -1211,7 +1193,7 @@ fl = (*seg->free_queues)[m->pool]; m_end = m + npages; /* Free blocks of increasing size. */ - lo = VM_PAGE_TO_PHYS(m) >> PAGE_SHIFT; + lo = atop(VM_PAGE_TO_PHYS(m)); if (m < m_end && (diff = lo ^ (lo + npages - 1)) != 0) { order = min(flsll(diff) - 1, VM_NFREEORDER - 1); @@ -1239,18 +1221,22 @@ void vm_phys_free_contig(vm_page_t m, u_long npages) { - int order_start, order_end; + vm_paddr_t lo; vm_page_t m_start, m_end; + unsigned max_order, order_start, order_end; vm_domain_free_assert_locked(vm_pagequeue_domain(m)); + lo = atop(VM_PAGE_TO_PHYS(m)); + max_order = min(flsll(lo ^ (lo + npages)) - 1, VM_NFREEORDER - 1); + m_start = m; - order_start = max_order(m_start); - if (order_start < VM_NFREEORDER - 1) + order_start = ffsll(lo) - 1; + if (order_start < max_order) m_start += 1 << order_start; m_end = m + npages; - order_end = max_order(m_end); - if (order_end < VM_NFREEORDER - 1) + order_end = ffsll(lo + npages) - 1; + if (order_end < max_order) m_end -= 1 << order_end; /* * Avoid unnecessary coalescing by freeing the pages at the start and @@ -1258,9 +1244,9 @@ */ if (m_start < m_end) vm_phys_enqueue_contig(m_start, m_end - m_start); - if (order_start < VM_NFREEORDER - 1) + if (order_start < max_order) vm_phys_free_pages(m, order_start); - if (order_end < VM_NFREEORDER - 1) + if (order_end < max_order) vm_phys_free_pages(m_end, order_end); } diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -237,6 +237,9 @@ vm_pindex_t size, i; int error, error1; + if (!dmar_rmrr_enable) + return (0); + error = 0; TAILQ_INIT(&rmrr_entries); dmar_dev_parse_rmrr(domain, dev_domain, dev_busno, dev_path, diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -319,6 +319,7 @@ extern int haw; extern int dmar_tbl_pagecnt; extern int dmar_batch_coalesce; +extern int dmar_rmrr_enable; static inline uint32_t dmar_read4(const struct dmar_unit *unit, int reg) diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -28,7 +28,6 @@ * SUCH DAMAGE. */ -#include #include "opt_acpi.h" #if defined(__amd64__) #define DEV_APIC @@ -157,6 +156,8 @@ return (1); } +int dmar_rmrr_enable = 1; + static int dmar_enable = 0; static void dmar_identify(driver_t *driver, device_t parent) @@ -171,6 +172,8 @@ TUNABLE_INT_FETCH("hw.dmar.enable", &dmar_enable); if (!dmar_enable) return; + TUNABLE_INT_FETCH("hw.dmar.rmrr_enable", &dmar_rmrr_enable); + status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl); if (ACPI_FAILURE(status)) return; @@ -906,6 +909,9 @@ char *ptr, *ptrend; int match; + if (!dmar_rmrr_enable) + return (1); + if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY) return (1); @@ -992,6 +998,9 @@ iria = arg; + if (!dmar_rmrr_enable) + return (1); + if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY) return (1); @@ -1019,10 +1028,10 @@ if (bootverbose) { printf("dmar%d no dev found for RMRR " "[%#jx, %#jx] rid %#x scope path ", - iria->dmar->iommu.unit, - (uintmax_t)resmem->BaseAddress, - (uintmax_t)resmem->EndAddress, - rid); + iria->dmar->iommu.unit, + (uintmax_t)resmem->BaseAddress, + (uintmax_t)resmem->EndAddress, + rid); dmar_print_path(devscope->Bus, dev_path_len, (const ACPI_DMAR_PCI_PATH *)(devscope + 1)); printf("\n"); diff --git a/sys/x86/iommu/intel_fault.c b/sys/x86/iommu/intel_fault.c --- a/sys/x86/iommu/intel_fault.c +++ b/sys/x86/iommu/intel_fault.c @@ -28,7 +28,6 @@ * SUCH DAMAGE. */ -#include #include "opt_acpi.h" #include diff --git a/sys/x86/iommu/intel_qi.c b/sys/x86/iommu/intel_qi.c --- a/sys/x86/iommu/intel_qi.c +++ b/sys/x86/iommu/intel_qi.c @@ -28,7 +28,6 @@ * SUCH DAMAGE. */ -#include #include "opt_acpi.h" #include diff --git a/tests/sys/fs/fusefs/Makefile b/tests/sys/fs/fusefs/Makefile --- a/tests/sys/fs/fusefs/Makefile +++ b/tests/sys/fs/fusefs/Makefile @@ -83,6 +83,10 @@ CXXWARNFLAGS.gcc+= -Wno-unused-but-set-variable # Suppress warnings about deprecated implicit copy constructors in gtest. CXXWARNFLAGS+= -Wno-deprecated-copy +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +# clang 18.0.0 introduces a new warning about variable length arrays in C++. +CXXWARNFLAGS+= -Wno-vla-cxx-extension +.endif CXXFLAGS+= -I${SRCTOP}/tests CXXFLAGS+= -I${FUSEFS} CXXFLAGS+= -I${MOUNT} diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh --- a/tests/sys/net/if_bridge_test.sh +++ b/tests/sys/net/if_bridge_test.sh @@ -663,6 +663,33 @@ vnet_cleanup } +atf_test_case "many_bridge_members" "cleanup" +many_bridge_members_head() +{ + atf_set descr 'many_bridge_members ifconfig test' + atf_set require.user root +} + +many_bridge_members_body() +{ + vnet_init + + bridge=$(vnet_mkbridge) + ifcount=256 + for _ in $(seq 1 $ifcount); do + epair=$(vnet_mkepair) + ifconfig "${bridge}" addm "${epair}"a + done + + atf_check -s exit:0 -o inline:"$ifcount\n" \ + sh -c "ifconfig ${bridge} | grep member: | wc -l | xargs" +} + +many_bridge_members_cleanup() +{ + vnet_cleanup +} + atf_init_test_cases() { atf_add_test_case "bridge_transmit_ipv4_unicast" @@ -677,4 +704,5 @@ atf_add_test_case "gif" atf_add_test_case "mtu" atf_add_test_case "vlan" + atf_add_test_case "many_bridge_members" } diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -127,6 +127,7 @@ OLD_FILES+=etc/autofs/special_noauto OLD_FILES+=etc/autofs/special_null OLD_FILES+=etc/auto_master +OLD_FILES+=etc/devd/autofs.conf OLD_FILES+=etc/rc.d/automount OLD_FILES+=etc/rc.d/automountd OLD_FILES+=etc/rc.d/autounmountd diff --git a/tools/tools/nanobsd/defaults.sh b/tools/tools/nanobsd/defaults.sh --- a/tools/tools/nanobsd/defaults.sh +++ b/tools/tools/nanobsd/defaults.sh @@ -884,7 +884,7 @@ # Call this function to set defaults _after_ parsing options. # dont want a subshell otherwise variable setting is thrown away. set_defaults_and_export ( ) { - : ${NANO_OBJ:=/usr/obj/nanobsd.${NANO_NAME}${NANO_LAYOUT}:+.${NANO_LAYOUT}} + : ${NANO_OBJ:=/usr/obj/nanobsd.${NANO_NAME}${NANO_LAYOUT:+.${NANO_LAYOUT}}} : ${MAKEOBJDIRPREFIX:=${NANO_OBJ}} : ${NANO_DISKIMGDIR:=${NANO_OBJ}} : ${NANO_WORLDDIR:=${NANO_OBJ}/_.w} diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1 --- a/usr.bin/diff/diff.1 +++ b/usr.bin/diff/diff.1 @@ -440,7 +440,7 @@ .It Fl -ignore-file-name-case ignore case when comparing file names .It Fl -no-ignore-file-name-case -do not ignore case wen comparing file names (default) +do not ignore case when comparing file names (default) .It Fl -normal default diff output .It Fl -speed-large-files diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1 --- a/usr.bin/find/find.1 +++ b/usr.bin/find/find.1 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 23, 2023 +.Dd December 22, 2023 .Dt FIND 1 .Os .Sh NAME @@ -347,6 +347,22 @@ .Ic -delete primary will fail to delete a directory if it is not empty. Following symlinks is incompatible with this option. +.Pp +.Em WARNING : +The +.Ic -delete +primary will immediately attempt to delete the current path when +evaluated. +Be mindful of its place in the expression; as a general rule, it +should almost always come last. +If in doubt, try running with +.Ic -print +in place of +.Ic -delete +first. +See +.Sx OPERATORS +below for additional information on the order of evaluation. .It Ic -depth Always true; same as the non-portable diff --git a/usr.bin/renice/tests/renice_test.sh b/usr.bin/renice/tests/renice_test.sh --- a/usr.bin/renice/tests/renice_test.sh +++ b/usr.bin/renice/tests/renice_test.sh @@ -14,8 +14,9 @@ atf_check_nice_value() { local pid=$1 - local nice=$2 - atf_check test "$(ps -o nice= -p $pid)" -eq "$nice" + local expected=$2 + local actual="$(ps -o nice= -p $pid)" + atf_check test "$actual" -eq "$expected" } atf_test_case renice_abs_pid @@ -57,7 +58,7 @@ renice_abs_pgid_body() { local pid pgid nice incr # make sure target runs in a different pgrp than ours - pid=$(sh -mc "sleep 60 >/dev/null & echo \$!") + pid="$(sh -mc "sleep 60 >/dev/null & echo \$!")" pgid="$(ps -o pgid= -p $pid)" nice="$(ps -o nice= -p $pid)" incr=3 @@ -73,7 +74,7 @@ renice_rel_pgid_body() { local pid pgid nice incr # make sure target runs in a different pgrp than ours - pid=$(sh -mc "sleep 60 >/dev/null & echo \$!") + pid="$(sh -mc "sleep 60 >/dev/null & echo \$!")" pgid="$(ps -o pgid= -p $pid)" nice="$(ps -o nice= -p $pid)" incr=3 @@ -90,7 +91,7 @@ } renice_abs_user_body() { local user pid nice incr - pid=$(su -m $TEST_USER -c "/bin/sh -c 'sleep 60 >/dev/null & echo \$!'") + pid="$(su -m $TEST_USER -c "/bin/sh -c 'sleep 60 >/dev/null & echo \$!'")" nice="$(ps -o nice= -p $pid)" incr=3 _renice $((nice+incr)) -u $TEST_USER @@ -105,7 +106,7 @@ } renice_rel_user_body() { local user pid nice incr - pid=$(su -m $TEST_USER -c "/bin/sh -c 'sleep 60 >/dev/null & echo \$!'") + pid="$(su -m $TEST_USER -c "/bin/sh -c 'sleep 60 >/dev/null & echo \$!'")" nice="$(ps -o nice= -p $pid)" incr=3 _renice -u -n $incr $TEST_USER diff --git a/usr.bin/seq/seq.c b/usr.bin/seq/seq.c --- a/usr.bin/seq/seq.c +++ b/usr.bin/seq/seq.c @@ -181,8 +181,9 @@ for (step = 1, cur = first; incr > 0 ? cur <= last : cur >= last; cur = first + incr * step++) { + if (step > 1) + fputs(sep, stdout); printf(fmt, cur); - fputs(sep, stdout); prev = cur; } @@ -202,15 +203,19 @@ } if (strcmp(cur_print, last_print) == 0 && strcmp(cur_print, prev_print) != 0) { - fputs(last_print, stdout); fputs(sep, stdout); + fputs(last_print, stdout); } free(cur_print); free(last_print); free(prev_print); - if (term != NULL) + if (term != NULL) { + fputs(sep, stdout); fputs(term, stdout); + } + + fputs("\n", stdout); return (0); } diff --git a/usr.sbin/bhyve/audio.c b/usr.sbin/bhyve/audio.c --- a/usr.sbin/bhyve/audio.c +++ b/usr.sbin/bhyve/audio.c @@ -80,6 +80,7 @@ #endif }; #endif + size_t nlen; assert(dev_name); @@ -87,8 +88,9 @@ if (!aud) return NULL; - if (strlen(dev_name) < sizeof(aud->dev_name)) - memcpy(aud->dev_name, dev_name, strlen(dev_name) + 1); + nlen = strlen(dev_name); + if (nlen < sizeof(aud->dev_name)) + memcpy(aud->dev_name, dev_name, nlen + 1); else { DPRINTF("dev_name too big"); free(aud); diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -196,16 +196,6 @@ Set configuration variables from a simple, key-value config file. Each line of the config file is expected to consist of a config variable name, an equals sign -.It Fl K Ar layout -Specify the keyboard layout. -The value that can be specified sets the file name in -.Ar /usr/share/bhyve/kbdlayout . -This specification only works when loaded with UEFI mode for VNC. -When using a VNC client that supports QEMU Extended Key Event Message (e.g. -TigerVNC), this option isn't needed. -When using a VNC client that doesn't support QEMU Extended Key Event Message -(e.g. tightVNC), the layout defaults to the US keyboard unless specified -otherwise. .Pq Sq = , and a value. No spaces are permitted between the variable name, equals sign, or @@ -216,6 +206,16 @@ See .Xr bhyve_config 5 for more details. +.It Fl K Ar layout +Specify the keyboard layout. +The value that can be specified sets the file name in +.Ar /usr/share/bhyve/kbdlayout . +This specification only works when loaded with UEFI mode for VNC. +When using a VNC client that supports QEMU Extended Key Event Message (e.g. +TigerVNC), this option isn't needed. +When using a VNC client that doesn't support QEMU Extended Key Event Message +(e.g. tightVNC), the layout defaults to the US keyboard unless specified +otherwise. .It Fl l Cm help Print a list of supported LPC devices. .It Fl l Ar lpcdev Ns Op Cm \&, Ns Ar conf @@ -245,7 +245,7 @@ .Sm on .Oc .Xc -Set the guest physical memory size +Set the guest physical memory size. This must be the same size that was given to .Xr bhyveload 8 . .Pp diff --git a/usr.sbin/bluetooth/hccontrol/bluetooth.device.conf b/usr.sbin/bluetooth/hccontrol/bluetooth.device.conf --- a/usr.sbin/bluetooth/hccontrol/bluetooth.device.conf +++ b/usr.sbin/bluetooth/hccontrol/bluetooth.device.conf @@ -61,8 +61,8 @@ # # Possible values: # -# NO or 0 do not scan for inquiry requests; -# YES or 1 scan for inquiry requests (default). +# NO or 0 do not scan for inquiry requests (default); +# YES or 1 scan for inquiry requests. # discoverable="NO" diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -532,6 +532,7 @@ { struct auth_group *ag; + assert(name != NULL); TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) return (ag); diff --git a/usr.sbin/ctld/uclparse.c b/usr.sbin/ctld/uclparse.c --- a/usr.sbin/ctld/uclparse.c +++ b/usr.sbin/ctld/uclparse.c @@ -60,6 +60,7 @@ const struct auth *ca; const ucl_object_t *user, *secret; + assert(auth_group != NULL); user = ucl_object_find_key(obj, "user"); if (!user || user->type != UCL_STRING) { log_warnx("chap section in auth-group \"%s\" is missing " @@ -90,6 +91,7 @@ const ucl_object_t *user, *secret, *mutual_user; const ucl_object_t *mutual_secret; + assert(auth_group != NULL); user = ucl_object_find_key(obj, "user"); if (!user || user->type != UCL_STRING) { log_warnx("chap-mutual section in auth-group \"%s\" is missing " @@ -714,6 +716,8 @@ } if (!strcmp(key, "auth-group")) { + const char *ag; + if (target->t_auth_group != NULL) { if (target->t_auth_group->ag_name != NULL) log_warnx("auth-group for target \"%s\" " @@ -725,8 +729,12 @@ "target \"%s\"", target->t_name); return (1); } - target->t_auth_group = auth_group_find(conf, - ucl_object_tostring(obj)); + ag = ucl_object_tostring(obj); + if (!ag) { + log_warnx("auth-group must be a string"); + return (1); + } + target->t_auth_group = auth_group_find(conf, ag); if (target->t_auth_group == NULL) { log_warnx("unknown auth-group \"%s\" for target " "\"%s\"", ucl_object_tostring(obj), @@ -759,6 +767,20 @@ } if (!strcmp(key, "chap")) { + if (target->t_auth_group != NULL) { + if (target->t_auth_group->ag_name != NULL) { + log_warnx("cannot use both auth-group " + "and chap for target \"%s\"", + target->t_name); + return (1); + } + } else { + target->t_auth_group = auth_group_new(conf, NULL); + if (target->t_auth_group == NULL) { + return (1); + } + target->t_auth_group->ag_target = target; + } if (uclparse_chap(target->t_auth_group, obj) != 0) return (1); } diff --git a/usr.sbin/kldxref/ef.c b/usr.sbin/kldxref/ef.c --- a/usr.sbin/kldxref/ef.c +++ b/usr.sbin/kldxref/ef.c @@ -361,6 +361,7 @@ goto out; } + nsym = 0; for (i = 0; i < nshdr; i++) { switch (shdr[i].sh_type) { case SHT_HASH: @@ -512,8 +513,8 @@ ofs = ef_get_offset(ef, address); if (ofs == 0) { if (ef->ef_verbose) - warnx("ef_seg_read_rel(%s): zero offset (%jx:%ju)", - ef->ef_name, (uintmax_t)address, (uintmax_t)ofs); + warnx("ef_seg_read_rel(%s): bad address (%jx)", + ef->ef_name, (uintmax_t)address); return (EFAULT); } error = elf_read_raw_data(ef->ef_efile, ofs, dest, len); @@ -542,7 +543,7 @@ int error; ofs = ef_get_offset(ef, address); - if (ofs == 0 || ofs == (GElf_Off)-1) { + if (ofs == 0) { if (ef->ef_verbose) warnx("ef_seg_read_string(%s): bad offset (%jx:%ju)", ef->ef_name, (uintmax_t)address, (uintmax_t)ofs); diff --git a/usr.sbin/kldxref/ef_obj.c b/usr.sbin/kldxref/ef_obj.c --- a/usr.sbin/kldxref/ef_obj.c +++ b/usr.sbin/kldxref/ef_obj.c @@ -46,7 +46,8 @@ #include "ef.h" typedef struct { - char *addr; + GElf_Addr addr; + GElf_Off offset; GElf_Off size; int flags; int sec; /* Original section */ @@ -69,9 +70,6 @@ char *ef_name; struct elf_file *ef_efile; - char *address; - GElf_Off size; - Elf_progent *progtab; int nprogtab; @@ -113,6 +111,22 @@ .lookup_set = ef_obj_lookup_set, }; +static GElf_Off +ef_obj_get_offset(elf_file_t ef, GElf_Addr addr) +{ + Elf_progent *pt; + int i; + + for (i = 0; i < ef->nprogtab; i++) { + pt = &ef->progtab[i]; + if (pt->offset == (GElf_Off)-1) + continue; + if (addr >= pt->addr && addr < pt->addr + pt->size) + return (pt->offset + (addr - pt->addr)); + } + return (0); +} + static int ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym) { @@ -139,9 +153,8 @@ for (i = 0; i < ef->nprogtab; i++) { if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && strcmp(ef->progtab[i].name + 4, name) == 0) { - *startp = ef->progtab[i].addr - ef->address; - *stopp = ef->progtab[i].addr + ef->progtab[i].size - - ef->address; + *startp = ef->progtab[i].addr; + *stopp = ef->progtab[i].addr + ef->progtab[i].size; *countp = (*stopp - *startp) / elf_pointer_size(ef->ef_efile); return (0); @@ -160,46 +173,50 @@ sym = ef->ddbsymtab + symidx; if (sym->st_shndx != SHN_UNDEF) - return (sym->st_value - (GElf_Addr)ef->address); + return (sym->st_value); return (0); } static int ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest) { - char *memaddr; + GElf_Off secofs; GElf_Rel *r; GElf_Rela *a; GElf_Addr secbase, dataoff; int error, i, sec; - if (address + len > ef->size) { - if (ef->ef_verbose) - warnx("ef_obj_seg_read_rel(%s): bad offset/len (%lx:%ld)", - ef->ef_name, (long)address, (long)len); - return (EFAULT); - } - bcopy(ef->address + address, dest, len); - /* Find out which section contains the data. */ - memaddr = ef->address + address; sec = -1; - secbase = dataoff = 0; for (i = 0; i < ef->nprogtab; i++) { - if (ef->progtab[i].addr == NULL) + if (address < ef->progtab[i].addr) continue; - if (memaddr < (char *)ef->progtab[i].addr || memaddr + len > - (char *)ef->progtab[i].addr + ef->progtab[i].size) + + dataoff = address - ef->progtab[i].addr; + if (dataoff + len > ef->progtab[i].size) continue; + sec = ef->progtab[i].sec; - /* We relocate to address 0. */ - secbase = (char *)ef->progtab[i].addr - ef->address; - dataoff = memaddr - ef->address; + secbase = ef->progtab[i].addr; + secofs = ef->progtab[i].offset; break; } - if (sec == -1) + if (sec == -1) { + if (ef->ef_verbose) + warnx("ef_obj_seg_read_rel(%s): bad address (%jx)", + ef->ef_name, (uintmax_t)address); return (EFAULT); + } + + if (secofs == (GElf_Off)-1) { + memset(dest, 0, len); + } else { + error = elf_read_raw_data(ef->ef_efile, secofs + dataoff, dest, + len); + if (error != 0) + return (error); + } /* Now do the relocations. */ for (i = 0; i < ef->nrel; i++) { @@ -208,7 +225,7 @@ for (r = ef->reltab[i].rel; r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) { error = elf_reloc(ef->ef_efile, r, ELF_T_REL, secbase, - dataoff, len, dest); + address, len, dest); if (error != 0) return (error); } @@ -219,7 +236,7 @@ for (a = ef->relatab[i].rela; a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) { error = elf_reloc(ef->ef_efile, a, ELF_T_RELA, secbase, - dataoff, len, dest); + address, len, dest); if (error != 0) return (error); } @@ -230,21 +247,23 @@ static int ef_obj_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char *dest) { + GElf_Off ofs; + int error; - if (address >= ef->size) { + ofs = ef_obj_get_offset(ef, address); + if (ofs == 0) { if (ef->ef_verbose) - warnx("ef_obj_seg_read_string(%s): bad address (%lx)", - ef->ef_name, (long)address); + warnx("ef_obj_seg_read_string(%s): bad address (%jx)", + ef->ef_name, (uintmax_t)address); return (EFAULT); } - if (ef->size - address < len) - len = ef->size - address; - - if (strnlen(ef->address + address, len) == len) + error = elf_read_raw_data(ef->ef_efile, ofs, dest, len); + if (error != 0) + return (error); + if (strnlen(dest, len) == len) return (EFAULT); - memcpy(dest, ef->address + address, len); return (0); } @@ -255,8 +274,8 @@ GElf_Ehdr *hdr; GElf_Shdr *shdr; GElf_Sym *es; - char *mapbase; - size_t i, mapsize, alignmask, max_addralign, nshdr; + GElf_Addr mapbase; + size_t i, nshdr; int error, pb, ra, rl; int j, nsym, symstrindex, symtabindex; @@ -359,59 +378,26 @@ } } - /* Size up code/data(progbits) and bss(nobits). */ - alignmask = 0; - max_addralign = 0; - mapsize = 0; - for (i = 0; i < nshdr; i++) { - switch (shdr[i].sh_type) { - case SHT_PROGBITS: - case SHT_NOBITS: - alignmask = shdr[i].sh_addralign - 1; - if (shdr[i].sh_addralign > max_addralign) - max_addralign = shdr[i].sh_addralign; - mapsize += alignmask; - mapsize &= ~alignmask; - mapsize += shdr[i].sh_size; - break; - } - } - - /* We know how much space we need for the text/data/bss/etc. */ - ef->size = mapsize; - if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { - printf("posix_memalign failed\n"); - goto out; - } - mapbase = ef->address; - /* - * Now load code/data(progbits), zero bss(nobits), allocate - * space for and load relocs + * Now allocate address space for code/data(progbits) and + * bss(nobits) and allocate space for and load relocs. */ pb = 0; rl = 0; ra = 0; - alignmask = 0; + mapbase = 0; for (i = 0; i < nshdr; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: - alignmask = shdr[i].sh_addralign - 1; - mapbase += alignmask; - mapbase = (char *)((uintptr_t)mapbase & ~alignmask); - ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; + mapbase = roundup2(mapbase, shdr[i].sh_addralign); + ef->progtab[pb].addr = mapbase; if (shdr[i].sh_type == SHT_PROGBITS) { ef->progtab[pb].name = "<>"; - if (elf_read_raw_data(efile, - shdr[i].sh_offset, ef->progtab[pb].addr, - shdr[i].sh_size) != 0) { - printf("failed to read progbits\n"); - goto out; - } + ef->progtab[pb].offset = shdr[i].sh_offset; } else { ef->progtab[pb].name = "<>"; - bzero(ef->progtab[pb].addr, shdr[i].sh_size); + ef->progtab[pb].offset = (GElf_Off)-1; } ef->progtab[pb].size = shdr[i].sh_size; ef->progtab[pb].sec = i; @@ -424,7 +410,7 @@ es = &ef->ddbsymtab[j]; if (es->st_shndx != i) continue; - es->st_value += (GElf_Addr)ef->progtab[pb].addr; + es->st_value += ef->progtab[pb].addr; } mapbase += shdr[i].sh_size; pb++; @@ -464,8 +450,6 @@ if (ef->ef_name) free(ef->ef_name); - if (ef->size != 0) - free(ef->address); if (ef->nprogtab != 0) free(ef->progtab); if (ef->nrel != 0) { diff --git a/usr.sbin/kldxref/elf.c b/usr.sbin/kldxref/elf.c --- a/usr.sbin/kldxref/elf.c +++ b/usr.sbin/kldxref/elf.c @@ -170,11 +170,7 @@ { ssize_t nread; - if (offset != (off_t)-1) { - if (lseek(efile->ef_fd, offset, SEEK_SET) == -1) - return (EIO); - } - nread = read(efile->ef_fd, dst, len); + nread = pread(efile->ef_fd, dst, len, offset); if (nread == -1) return (errno); if (nread != len) diff --git a/usr.sbin/mountd/exports.5 b/usr.sbin/mountd/exports.5 --- a/usr.sbin/mountd/exports.5 +++ b/usr.sbin/mountd/exports.5 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 16, 2022 +.Dd December 21, 2023 .Dt EXPORTS 5 .Os .Sh NAME @@ -106,6 +106,17 @@ or .Dq Pa .. components. +Pathnames are decoded by +.Xr strunvis 3 +allowing special characters to be included in the directory name(s). +In particular, whitespace, such as embedded blanks in directory names +can be handled. +For example, a blank can be encoded as \(rs040. +.Xr vis 1 +with the +.Fl M +option may be used to encode directory name(s) with embedded special +characters. Mount points for a file system may appear on multiple lines each with different sets of hosts and export options. .Pp @@ -582,6 +593,8 @@ permission for will succeed and read/write access will fail afterwards, whereas NFSv3 rejects the mount request. .Sh SEE ALSO +.Xr vis 1 , +.Xr strunvis 3 , .Xr nfsv4 4 , .Xr netgroup 5 , .Xr mountd 8 , diff --git a/usr.sbin/newsyslog/newsyslog.8 b/usr.sbin/newsyslog/newsyslog.8 --- a/usr.sbin/newsyslog/newsyslog.8 +++ b/usr.sbin/newsyslog/newsyslog.8 @@ -14,7 +14,7 @@ .\" the suitability of this software for any purpose. It is .\" provided "as is" without express or implied warranty. .\" -.Dd November 10, 2018 +.Dd December 22, 2023 .Dt NEWSYSLOG 8 .Os .Sh NAME @@ -24,6 +24,7 @@ .Nm .Op Fl CFNPnrsv .Op Fl a Ar directory +.Op Fl c Ar none Ns | Ns Ar legacy Ns | Ns Ar bzip2 Ns | Ns Ar gzip Ns | Ns Ar xz Ns | Ns Ar zstd .Op Fl d Ar directory .Op Fl f Ar config_file .Op Fl S Ar pidfile @@ -78,6 +79,25 @@ The following options can be used with .Nm : .Bl -tag -width indent +.It Fl c Ar none Ns | Ns Ar legacy Ns | Ns Ar bzip2 Ns | Ns Ar gzip Ns | Ns Ar xz Ns | Ns Ar zstd +Instructs +.Nm +to use the specified compression method when a file is flagged for compression. +The default method is +.Dq legacy , +which interprets the +.Sy J, X, Y, Z +flags in the configuration file according to their historical meanings. +This default setting can be overridden by specifying +.Fl c Ar none , +which causes +.Nm +to ignore all compression flags. +Alternatively, specifying one of the compression methods: +.Sy bzip2 , gzip , xz , +or +.Sy zstd , +will apply the chosen method to all files flagged for compression. .It Fl f Ar config_file Instruct .Nm diff --git a/usr.sbin/newsyslog/newsyslog.c b/usr.sbin/newsyslog/newsyslog.c --- a/usr.sbin/newsyslog/newsyslog.c +++ b/usr.sbin/newsyslog/newsyslog.c @@ -88,13 +88,15 @@ /* * Compression types */ -#define COMPRESS_TYPES 5 /* Number of supported compression types */ - -#define COMPRESS_NONE 0 -#define COMPRESS_GZIP 1 -#define COMPRESS_BZIP2 2 -#define COMPRESS_XZ 3 -#define COMPRESS_ZSTD 4 +enum compress_types_enum { + COMPRESS_NONE = 0, + COMPRESS_GZIP = 1, + COMPRESS_BZIP2 = 2, + COMPRESS_XZ = 3, + COMPRESS_ZSTD = 4, + COMPRESS_LEGACY = 5, /* Special: use legacy type */ + COMPRESS_TYPES = COMPRESS_LEGACY /* Number of supported compression types */ +}; /* * Bit-values for the 'flags' parsed from a config-file entry. @@ -127,6 +129,7 @@ #define MAX_OLDLOGS 65536 /* Default maximum number of old logfiles */ struct compress_types { + const char *name; /* Name of compression type */ const char *flag; /* Flag in configuration file */ const char *suffix; /* Compression suffix */ const char *path; /* Path to compression program */ @@ -137,14 +140,29 @@ static const char *gzip_flags[] = { "-f" }; #define bzip2_flags gzip_flags #define xz_flags gzip_flags -static const char *zstd_flags[] = { "-q", "--rm" }; - -static const struct compress_types compress_type[COMPRESS_TYPES] = { - { "", "", "", NULL, 0 }, - { "Z", ".gz", _PATH_GZIP, gzip_flags, nitems(gzip_flags) }, - { "J", ".bz2", _PATH_BZIP2, bzip2_flags, nitems(bzip2_flags) }, - { "X", ".xz", _PATH_XZ, xz_flags, nitems(xz_flags) }, - { "Y", ".zst", _PATH_ZSTD, zstd_flags, nitems(zstd_flags) } +static const char *zstd_flags[] = { "-q", "-T0", "--adapt", "--long", "--rm" }; + +static struct compress_types compress_type[COMPRESS_TYPES] = { + [COMPRESS_NONE] = { + .name = "none", .flag = "", .suffix = "", + .path = "", .flags = NULL, .nflags = 0 + }, + [COMPRESS_GZIP] = { + .name = "gzip", .flag = "Z", .suffix = ".gz", + .path = _PATH_GZIP, .flags = gzip_flags, .nflags = nitems(gzip_flags) + }, + [COMPRESS_BZIP2] = { + .name = "bzip2", .flag = "J", .suffix = ".bz2", + .path = _PATH_BZIP2, .flags = bzip2_flags, .nflags = nitems(bzip2_flags) + }, + [COMPRESS_XZ] = { + .name = "xz", .flag = "X", .suffix = ".xz", + .path = _PATH_XZ, .flags = xz_flags, .nflags = nitems(xz_flags) + }, + [COMPRESS_ZSTD] = { + .name = "zstd", .flag = "Y", .suffix = ".zst", + .path = _PATH_ZSTD, .flags = zstd_flags, .nflags = nitems(zstd_flags) + }, }; struct conf_entry { @@ -229,6 +247,7 @@ static char *archdirname; /* Directory path to old logfiles archive */ static char *destdir = NULL; /* Directory to treat at root for logs */ static const char *conf; /* Configuration file to use */ +static enum compress_types_enum compress_type_override = COMPRESS_LEGACY; /* Compression type */ struct ptime_data *dbg_timenow; /* A "timenow" value set via -D option */ static struct ptime_data *timenow; /* The time to use for checking at-fields */ @@ -628,7 +647,7 @@ static void parse_args(int argc, char **argv) { - int ch; + int ch, i; char *p; timenow = ptime_init(NULL); @@ -641,12 +660,28 @@ hostname_shortlen = strcspn(hostname, "."); /* Parse command line options. */ - while ((ch = getopt(argc, argv, "a:d:f:nrst:vCD:FNPR:S:")) != -1) + while ((ch = getopt(argc, argv, "a:c:d:f:nrst:vCD:FNPR:S:")) != -1) switch (ch) { case 'a': archtodir++; archdirname = optarg; break; + case 'c': + for (i = 0; i < COMPRESS_TYPES; i++) { + if (strcmp(optarg, compress_type[i].name) == 0) { + compress_type_override = i; + break; + } + } + if (i == COMPRESS_TYPES) { + if (strcmp(optarg, "legacy") == 0) + compress_type_override = COMPRESS_LEGACY; + else { + warnx("Unrecognized compression method '%s'.", optarg); + usage(); + } + } + break; case 'd': destdir = optarg; break; @@ -791,10 +826,26 @@ static void usage(void) { + int i; + char *alltypes = NULL, *tmp = NULL; + + for (i = 0; i < COMPRESS_TYPES; i++) { + if (i == COMPRESS_NONE) { + (void)asprintf(&tmp, "%s|legacy", compress_type[i].name); + } else { + (void)asprintf(&tmp, "%s|%s", alltypes, compress_type[i].name); + } + if (alltypes) + free(alltypes); + alltypes = tmp; + tmp = NULL; + } fprintf(stderr, - "usage: newsyslog [-CFNPnrsv] [-a directory] [-d directory] [-f config_file]\n" - " [-S pidfile] [-t timefmt] [[-R tagname] file ...]\n"); + "usage: newsyslog [-CFNPnrsv] [-a directory] [-c %s]\n" + " [-d directory] [-f config_file]\n" + " [-S pidfile] [-t timefmt] [[-R tagname] file ...]\n", + alltypes); exit(1); } @@ -1302,7 +1353,10 @@ working->flags |= CE_GLOB; break; case 'j': - working->compress = COMPRESS_BZIP2; + if (compress_type_override == COMPRESS_LEGACY) + working->compress = COMPRESS_BZIP2; + else + working->compress = compress_type_override; break; case 'n': working->flags |= CE_NOSIGNAL; @@ -1323,13 +1377,22 @@ /* Deprecated flag - keep for compatibility purposes */ break; case 'x': - working->compress = COMPRESS_XZ; + if (compress_type_override == COMPRESS_LEGACY) + working->compress = COMPRESS_XZ; + else + working->compress = compress_type_override; break; case 'y': - working->compress = COMPRESS_ZSTD; + if (compress_type_override == COMPRESS_LEGACY) + working->compress = COMPRESS_ZSTD; + else + working->compress = compress_type_override; break; case 'z': - working->compress = COMPRESS_GZIP; + if (compress_type_override == COMPRESS_LEGACY) + working->compress = COMPRESS_GZIP; + else + working->compress = compress_type_override; break; case '-': break; @@ -2035,6 +2098,7 @@ assert(zwork->zw_conf != NULL); assert(zwork->zw_conf->compress > COMPRESS_NONE); assert(zwork->zw_conf->compress < COMPRESS_TYPES); + assert(zwork->zw_conf->compress != COMPRESS_LEGACY); if (zwork->zw_swork != NULL && zwork->zw_swork->sw_runcmd == 0 && zwork->zw_swork->sw_pidok <= 0) { diff --git a/usr.sbin/newsyslog/newsyslog.conf.5 b/usr.sbin/newsyslog/newsyslog.conf.5 --- a/usr.sbin/newsyslog/newsyslog.conf.5 +++ b/usr.sbin/newsyslog/newsyslog.conf.5 @@ -18,7 +18,7 @@ .\" the suitability of this software for any purpose. It is .\" provided "as is" without express or implied warranty. .\" -.Dd February 26, 2021 +.Dd December 22, 2023 .Dt NEWSYSLOG.CONF 5 .Os .Sh NAME @@ -308,8 +308,11 @@ .It Cm J indicates that .Xr newsyslog 8 -should attempt to save disk space by compressing the rotated -log file using +should consider the rotated log file as compressible. +In legacy mode, +this also tells +.Xr newsyslog 8 +to use .Xr bzip2 1 . .It Cm N indicates that there is no process which needs to be signaled @@ -337,20 +340,29 @@ .It Cm X indicates that .Xr newsyslog 8 -should attempt to save disk space by compressing the rotated -log file using +should consider the rotated log file as compressible. +In legacy mode, +this also tells +.Xr newsyslog 8 +to use .Xr xz 1 . .It Cm Y indicates that .Xr newsyslog 8 -should attempt to save disk space by compressing the rotated -log file using +should consider the rotated log file as compressible. +In legacy mode, +this also tells +.Xr newsyslog 8 +to use .Xr zstd 1 . .It Cm Z indicates that .Xr newsyslog 8 -should attempt to save disk space by compressing the rotated -log file using +should consider the rotated log file as compressible. +In legacy mode, +this also tells +.Xr newsyslog 8 +to use .Xr gzip 1 . .It Fl a minus sign will not cause any special processing, but it diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c --- a/usr.sbin/pwd_mkdb/pwd_mkdb.c +++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c @@ -94,10 +94,11 @@ uint32_t store; const char *t; char *p; - char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; + char buf[MAX(MAXPATHLEN, LINE_MAX * 2)]; char sbuf[MAX(MAXPATHLEN, LINE_MAX * 2)]; char buf2[MAXPATHLEN]; char sbuf2[MAXPATHLEN]; + char tbuf[1024]; char *username; u_int method, methoduid; int Cflag, dflag, iflag;