diff --git a/include/fts.h b/include/fts.h --- a/include/fts.h +++ b/include/fts.h @@ -34,17 +34,27 @@ #include +typedef struct _ftsent FTSENT; + typedef struct { - struct _ftsent *fts_cur; /* current node */ - struct _ftsent *fts_child; /* linked list of children */ - struct _ftsent **fts_array; /* sort array */ + FTSENT *fts_cur; /* current node */ + FTSENT *fts_child; /* linked list of children */ + FTSENT **fts_array; /* sort array */ __dev_t fts_dev; /* starting device # */ char *fts_path; /* path for this descent */ int fts_rfd; /* fd for root */ __size_t fts_pathlen; /* sizeof(path) */ __size_t fts_nitems; /* elements in the sort array */ - int (*fts_compar) /* compare function */ - (const struct _ftsent * const *, const struct _ftsent * const *); + union { + int (*fts_compar) /* compare function */ + (const FTSENT * const *, const FTSENT * const *); +#ifdef __BLOCKS__ + int (^fts_compar_b) + (const FTSENT * const *, const FTSENT * const *); +#else + void *fts_compar_b; +#endif /* __BLOCKS__ */ + }; /* valid for fts_open() */ #define FTS_COMFOLLOW 0x000001 /* follow command line symlinks */ @@ -62,11 +72,12 @@ /* internal use only */ #define FTS_STOP 0x010000 /* unrecoverable error */ +#define FTS_COMPAR_B 0x020000 /* compare function is a block */ int fts_options; /* fts_open options, global flags */ void *fts_clientptr; /* thunk for sort function */ } FTS; -typedef struct _ftsent { +struct _ftsent { struct _ftsent *fts_cycle; /* cycle node */ struct _ftsent *fts_parent; /* parent directory */ struct _ftsent *fts_link; /* next file in directory */ @@ -118,7 +129,7 @@ struct stat *fts_statp; /* stat(2) information */ char *fts_name; /* file name */ FTS *fts_fts; /* back pointer to main FTS */ -} FTSENT; +}; #include @@ -131,6 +142,10 @@ #define fts_get_stream(ftsent) ((ftsent)->fts_fts) FTS *fts_open(char * const *, int, int (*)(const FTSENT * const *, const FTSENT * const *)); +#ifdef __BLOCKS__ +FTS *fts_open_b(char * const *, int, + int (^)(const FTSENT * const *, const FTSENT * const *)); +#endif /* __BLOCKS__ */ FTSENT *fts_read(FTS *); int fts_set(FTS *, FTSENT *, int); void fts_set_clientptr(FTS *, void *); diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -168,6 +168,10 @@ valloc.c \ wordexp.c +.if ${COMPILER_FEATURES:Mblocks} +CFLAGS.fts.c= -fblocks +.endif + CFLAGS.arc4random.c= -I${SRCTOP}/sys -I${SRCTOP}/sys/crypto/chacha20 CFLAGS.sysconf.c= -I${SRCTOP}/contrib/tzcode diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -458,6 +458,7 @@ aio_read2; aio_write2; execvpe; + fts_open_b; psiginfo; rtld_get_var; rtld_set_var; diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c --- a/lib/libc/gen/exec.c +++ b/lib/libc/gen/exec.c @@ -136,7 +136,7 @@ int execvp(const char *name, char * const *argv) { - return (execvpe(name, argv, environ)); + return (__libc_execvpe(name, argv, environ)); } static int @@ -288,7 +288,7 @@ } int -execvpe(const char *name, char * const argv[], char * const envp[]) +__libc_execvpe(const char *name, char * const argv[], char * const envp[]) { const char *path; @@ -298,3 +298,5 @@ return (execvPe(name, path, argv, envp)); } + +__weak_reference(__libc_execvpe, execvpe); diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 12, 2014 +.Dd April 17, 2025 .Dt FTS 3 .Os .Sh NAME @@ -37,6 +37,8 @@ .In fts.h .Ft FTS * .Fn fts_open "char * const *path_argv" "int options" "int (*compar)(const FTSENT * const *, const FTSENT * const *)" +.Ft FTS * +.Fn fts_open_b "char * const *path_argv" "int options" "int (^compar)(const FTSENT * const *, const FTSENT * const *)" .Ft FTSENT * .Fn fts_read "FTS *ftsp" .Ft FTSENT * @@ -59,7 +61,9 @@ file hierarchies. A simple overview is that the .Fn fts_open -function returns a +and +.Fn fts_open_b +functions return a .Dq handle on a file hierarchy, which is then supplied to the other @@ -186,6 +190,8 @@ .Ql ..\& which was not specified as a file name to .Fn fts_open +or +.Fn fts_open_b (see .Dv FTS_SEEDOT ) . .It Dv FTS_DP @@ -234,6 +240,8 @@ The path for the file relative to the root of the traversal. This path contains the path specified to .Fn fts_open +or +.Fn fts_open_b as a prefix. .It Fa fts_pathlen The length of the string referenced by @@ -518,6 +526,15 @@ .Fa path_argv for the root paths, and in the order listed in the directory for everything else. +.Sh FTS_OPEN_B +The +.Fn fts_open_b +function is identical to +.Fn fts_open +except that it takes a block pointer instead of a function pointer. +The block is copied before +.Fn fts_open_b +returns, so the original can safely go out of scope or be released. .Sh FTS_READ The .Fn fts_read @@ -593,9 +610,13 @@ has not yet been called for a hierarchy, .Fn fts_children will return a pointer to the files in the logical directory specified to -.Fn fts_open , +.Fn fts_open +or +.Fn fts_open_b , i.e., the arguments specified to -.Fn fts_open . +.Fn fts_open +or +.Fn fts_open_b . Otherwise, if the .Vt FTSENT structure most recently returned by @@ -716,6 +737,8 @@ .Fa ftsp and restores the current directory to the directory from which .Fn fts_open +or +.Fn fts_open_b was called to open .Fa ftsp . The @@ -723,29 +746,38 @@ function returns 0 on success, and \-1 if an error occurs. .Sh ERRORS -The function +The .Fn fts_open -may fail and set +and +.Fn fts_open_b +functions may fail and set .Va errno for any of the errors specified for the library functions .Xr open 2 and .Xr malloc 3 . +The +.Fn fts_open_b +function may also fail and set +.Va errno +to +.Dv ENOSYS +if the blocks runtime is missing. .Pp -The function +The .Fn fts_close -may fail and set +function may fail and set .Va errno for any of the errors specified for the library functions .Xr chdir 2 and .Xr close 2 . .Pp -The functions +The .Fn fts_read and .Fn fts_children -may fail and set +functions may fail and set .Va errno for any of the errors specified for the library functions .Xr chdir 2 , @@ -755,12 +787,12 @@ and .Xr stat 2 . .Pp -In addition, +In addition, the .Fn fts_children , -.Fn fts_open +.Fn fts_open , and .Fn fts_set -may fail and set +functions may fail and set .Va errno as follows: .Bl -tag -width Er diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -48,6 +48,19 @@ #include "gen-private.h" +#ifdef __BLOCKS__ +#include +#else +#include "block_abi.h" +typedef DECLARE_BLOCK(int, fts_block, + const FTSENT * const *, const FTSENT * const *); +void qsort_b(void *, size_t, size_t, fts_block); +#endif /* __BLOCKS__ */ +/* only present if linked with blocks runtime */ +void *_Block_copy(const void *) __weak_symbol; +void _Block_release(const void *) __weak_symbol; +extern void *_NSConcreteGlobalBlock[] __weak_symbol; + static FTSENT *fts_alloc(FTS *, char *, size_t); static FTSENT *fts_build(FTS *, int); static void fts_lfree(FTSENT *); @@ -102,35 +115,13 @@ 0 }; -FTS * -fts_open(char * const *argv, int options, - int (*compar)(const FTSENT * const *, const FTSENT * const *)) +static FTS * +__fts_open(FTS *sp, char * const *argv) { - struct _fts_private *priv; - FTS *sp; FTSENT *p, *root; FTSENT *parent, *tmp; size_t len, nitems; - /* Options check. */ - if (options & ~FTS_OPTIONMASK) { - errno = EINVAL; - return (NULL); - } - - /* fts_open() requires at least one path */ - if (*argv == NULL) { - errno = EINVAL; - return (NULL); - } - - /* Allocate/initialize the stream. */ - if ((priv = calloc(1, sizeof(*priv))) == NULL) - return (NULL); - sp = &priv->ftsp_fts; - sp->fts_compar = compar; - sp->fts_options = options; - /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ if (ISSET(FTS_LOGICAL)) SET(FTS_NOCHDIR); @@ -168,7 +159,7 @@ * If comparison routine supplied, traverse in sorted * order; otherwise traverse in the order specified. */ - if (compar) { + if (sp->fts_compar) { p->fts_link = root; root = p; } else { @@ -181,7 +172,7 @@ } } } - if (compar && nitems > 1) + if (sp->fts_compar && nitems > 1) root = fts_sort(sp, root, nitems); /* @@ -214,6 +205,97 @@ return (NULL); } +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT * const *, const FTSENT * const *)) +{ + struct _fts_private *priv; + FTS *sp; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; + sp->fts_compar = compar; + sp->fts_options = options; + + return (__fts_open(sp, argv)); +} + +#ifdef __BLOCKS__ +FTS * +fts_open_b(char * const *argv, int options, + int (^compar)(const FTSENT * const *, const FTSENT * const *)) +#else +FTS * +fts_open_b(char * const *argv, int options, fts_block compar) +#endif /* __BLOCKS__ */ +{ + struct _fts_private *priv; + FTS *sp; + + /* No blocks, no problems. */ + if (compar == NULL) + return (fts_open(argv, options, NULL)); + + /* Avoid segfault if blocks runtime is missing. */ + if (_Block_copy == NULL) { + errno = ENOSYS; + return (NULL); + } + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; +#ifdef __BLOCKS__ + compar = Block_copy(compar); +#else + if (compar->isa != &_NSConcreteGlobalBlock) + compar = _Block_copy(compar); +#endif /* __BLOCKS__ */ + if (compar == NULL) { + free(priv); + return (NULL); + } + sp->fts_compar_b = compar; + sp->fts_options = options | FTS_COMPAR_B; + + if ((sp = __fts_open(sp, argv)) == NULL) { +#ifdef __BLOCKS__ + Block_release(compar); +#else + if (compar->isa != &_NSConcreteGlobalBlock) + _Block_release(compar); +#endif /* __BLOCKS__ */ + } + return (sp); +} + static void fts_load(FTS *sp, FTSENT *p) { @@ -265,6 +347,16 @@ free(sp->fts_array); free(sp->fts_path); + /* Free up any block pointer. */ + if (ISSET(FTS_COMPAR_B) && sp->fts_compar_b != NULL) { +#ifdef __BLOCKS__ + Block_release(sp->fts_compar_b); +#else + if (sp->fts_compar_b->isa != &_NSConcreteGlobalBlock) + _Block_release(sp->fts_compar_b); +#endif /* __BLOCKS__ */ + } + /* Return to original directory, save errno if necessary. */ if (!ISSET(FTS_NOCHDIR)) { saved_errno = fchdir(sp->fts_rfd) ? errno : 0; @@ -979,21 +1071,6 @@ return (FTS_DEFAULT); } -/* - * The comparison function takes pointers to pointers to FTSENT structures. - * Qsort wants a comparison function that takes pointers to void. - * (Both with appropriate levels of const-poisoning, of course!) - * Use a trampoline function to deal with the difference. - */ -static int -fts_compar(const void *a, const void *b) -{ - FTS *parent; - - parent = (*(const FTSENT * const *)a)->fts_fts; - return (*parent->fts_compar)(a, b); -} - static FTSENT * fts_sort(FTS *sp, FTSENT *head, size_t nitems) { @@ -1016,7 +1093,18 @@ } for (ap = sp->fts_array, p = head; p; p = p->fts_link) *ap++ = p; - qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); + if (ISSET(FTS_COMPAR_B)) { +#ifdef __BLOCKS__ + qsort_b(sp->fts_array, nitems, sizeof(FTSENT *), + (int (^)(const void *, const void *))sp->fts_compar_b); +#else + qsort_b(sp->fts_array, nitems, sizeof(FTSENT *), + sp->fts_compar_b); +#endif /* __BLOCKS__ */ + } else { + qsort(sp->fts_array, nitems, sizeof(FTSENT *), + (int (*)(const void *, const void *))sp->fts_compar); + } for (head = *(ap = sp->fts_array); --nitems; ++ap) ap[0]->fts_link = ap[1]; ap[0]->fts_link = NULL; diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c --- a/lib/libc/gen/posix_spawn.c +++ b/lib/libc/gen/posix_spawn.c @@ -261,7 +261,7 @@ } envp = psa->envp != NULL ? psa->envp : environ; if (psa->use_env_path) - execvpe(psa->path, psa->argv, envp); + __libc_execvpe(psa->path, psa->argv, envp); else _execve(psa->path, psa->argv, envp); psa->error = errno; diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -345,6 +345,7 @@ struct __wrusage; enum idtype; +int __libc_execvpe(const char *, char * const *, char * const *); int __libc_sigaction(int, const struct sigaction *, struct sigaction *) __hidden; int __libc_sigprocmask(int, const __sigset_t *, __sigset_t *) diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile --- a/lib/libc/tests/gen/Makefile +++ b/lib/libc/tests/gen/Makefile @@ -7,6 +7,9 @@ ATF_TESTS_C+= fmtmsg_test ATF_TESTS_C+= fnmatch2_test ATF_TESTS_C+= fpclassify2_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= fts_blocks_test +.endif ATF_TESTS_C+= ftw_test ATF_TESTS_C+= getentropy_test ATF_TESTS_C+= getmntinfo_test @@ -92,6 +95,12 @@ TESTS_SUBDIRS= execve TESTS_SUBDIRS+= posix_spawn +# Tests that require blocks support +.for t in fts_blocks_test +CFLAGS.${t}.c+= -fblocks +LIBADD.${t}+= BlocksRuntime +.endfor + # The old testcase name TEST_FNMATCH= test-fnmatch CLEANFILES+= ${GEN_SH_CASE_TESTCASES} diff --git a/lib/libc/tests/gen/fts_blocks_test.c b/lib/libc/tests/gen/fts_blocks_test.c new file mode 100644 --- /dev/null +++ b/lib/libc/tests/gen/fts_blocks_test.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include + +#include + +/* + * Create two directories with three files each in lexicographical order, + * then call FTS with a sort block that sorts in reverse lexicographical + * order. This has the least chance of getting a false positive due to + * differing file system semantics. UFS will return the files in the + * order they were created while ZFS will sort them lexicographically; in + * both cases, the order we expect is the reverse. + */ +ATF_TC_WITHOUT_HEAD(fts_blocks_test); +ATF_TC_BODY(fts_blocks_test, tc) +{ + char *args[] = { + "bar", "foo", NULL + }; + char *paths[] = { + "foo", "z", "y", "x", "foo", + "bar", "c", "b", "a", "bar", + NULL + }; + char **expect = paths; + FTS *fts; + FTSENT *ftse; + + ATF_REQUIRE_EQ(0, mkdir("bar", 0755)); + ATF_REQUIRE_EQ(0, close(creat("bar/a", 0644))); + ATF_REQUIRE_EQ(0, close(creat("bar/b", 0644))); + ATF_REQUIRE_EQ(0, close(creat("bar/c", 0644))); + ATF_REQUIRE_EQ(0, mkdir("foo", 0755)); + ATF_REQUIRE_EQ(0, close(creat("foo/x", 0644))); + ATF_REQUIRE_EQ(0, close(creat("foo/y", 0644))); + ATF_REQUIRE_EQ(0, close(creat("foo/z", 0644))); + fts = fts_open_b(args, 0, + ^(const FTSENT * const *a, const FTSENT * const *b) { + return (strcmp((*b)->fts_name, (*a)->fts_name)); + }); + ATF_REQUIRE_MSG(fts != NULL, "fts_open_b(): %m"); + while ((ftse = fts_read(fts)) != NULL && *expect != NULL) { + ATF_CHECK_STREQ(*expect, ftse->fts_name); + expect++; + } + ATF_CHECK_EQ(NULL, ftse); + ATF_CHECK_EQ(NULL, *expect); + ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, fts_blocks_test); + return (atf_no_error()); +} diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile --- a/lib/libc/tests/stdlib/Makefile +++ b/lib/libc/tests/stdlib/Makefile @@ -7,7 +7,7 @@ ATF_TESTS_C+= libc_exit_test ATF_TESTS_C+= mergesort_test ATF_TESTS_C+= qsort_test -.if ${COMPILER_TYPE} == "clang" +.if ${COMPILER_FEATURES:Mblocks} ATF_TESTS_C+= qsort_b_test .endif ATF_TESTS_C+= qsort_r_compat_test @@ -61,7 +61,7 @@ LIBADD.cxa_thread_atexit_test+= pthread -# Tests that requires Blocks feature +# Tests that require blocks support .for t in qsort_b_test CFLAGS.${t}.c+= -fblocks LIBADD.${t}+= BlocksRuntime diff --git a/share/mk/Makefile b/share/mk/Makefile --- a/share/mk/Makefile +++ b/share/mk/Makefile @@ -50,6 +50,7 @@ bsd.progs.mk \ bsd.snmpmod.mk \ bsd.subdir.mk \ + bsd.suffixes-extra.mk \ bsd.suffixes-posix.mk \ bsd.suffixes.mk \ bsd.symver.mk \ diff --git a/share/mk/bsd.compiler.mk b/share/mk/bsd.compiler.mk --- a/share/mk/bsd.compiler.mk +++ b/share/mk/bsd.compiler.mk @@ -245,6 +245,7 @@ ${X_}COMPILER_FEATURES+= init-all .endif .if ${${X_}COMPILER_TYPE} == "clang" +${X_}COMPILER_FEATURES+= blocks ${X_}COMPILER_FEATURES+= retpoline # PR257638 lld fails with BE compressed debug. Fixed in main but external tool # chains will initially not have the fix. For now limit the feature to LE diff --git a/share/mk/bsd.lib.mk b/share/mk/bsd.lib.mk --- a/share/mk/bsd.lib.mk +++ b/share/mk/bsd.lib.mk @@ -148,79 +148,7 @@ .include -# prefer .s to a .c, remove stuff not used in the BSD libraries -# .pico used for PIC object files -# .nossppico used for NOSSP PIC object files -# .pieo used for PIE object files -.SUFFIXES: .out .o .bc .ll .pico .nossppico .pieo .S .asm .s .c .cc .cpp .cxx .C .f .y .l .ln - -.if !defined(PICFLAG) -PICFLAG=-fpic -PIEFLAG=-fpie -.endif - -.c.pico: - ${CC} ${PICFLAG} -DPIC ${SHARED_CFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.c.nossppico: - ${CC} ${PICFLAG} -DPIC ${SHARED_CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} ${CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.c.pieo: - ${CC} ${PIEFLAG} -DPIC ${SHARED_CFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.cc.pico .C.pico .cpp.pico .cxx.pico: - ${CXX} ${PICFLAG} -DPIC ${SHARED_CXXFLAGS} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET} - -.cc.nossppico .C.nossppico .cpp.nossppico .cxx.nossppico: - ${CXX} ${PICFLAG} -DPIC ${SHARED_CXXFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} ${CXXFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} -c ${.IMPSRC} -o ${.TARGET} - -.cc.pieo .C.pieo .cpp.pieo .cxx.pieo: - ${CXX} ${PIEFLAG} ${SHARED_CXXFLAGS} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET} - -.f.pico: - ${FC} ${PICFLAG} -DPIC ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC} - ${CTFCONVERT_CMD} - -.f.nossppico: - ${FC} ${PICFLAG} -DPIC ${FFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//} -o ${.TARGET} -c ${.IMPSRC} - ${CTFCONVERT_CMD} - -.s.pico .s.nossppico .s.pieo: - ${CC:N${CCACHE_BIN}} -x assembler ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.asm.pico: - ${CC:N${CCACHE_BIN}} -x assembler-with-cpp ${PICFLAG} -DPIC \ - ${CFLAGS} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.asm.nossppico: - ${CC:N${CCACHE_BIN}} -x assembler-with-cpp ${PICFLAG} -DPIC \ - ${CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.asm.pieo: - ${CC:N${CCACHE_BIN}} -x assembler-with-cpp ${PIEFLAG} -DPIC \ - ${CFLAGS} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.S.pico: - ${CC:N${CCACHE_BIN}} ${PICFLAG} -DPIC ${CFLAGS} ${ACFLAGS} \ - -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.S.nossppico: - ${CC:N${CCACHE_BIN}} ${PICFLAG} -DPIC ${CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//} ${ACFLAGS} \ - -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} - -.S.pieo: - ${CC:N${CCACHE_BIN}} ${PIEFLAG} -DPIC ${CFLAGS} ${ACFLAGS} \ - -c ${.IMPSRC} -o ${.TARGET} - ${CTFCONVERT_CMD} +.include _LIBDIR:=${LIBDIR} _SHLIBDIR:=${SHLIBDIR} diff --git a/share/mk/bsd.prog.mk b/share/mk/bsd.prog.mk --- a/share/mk/bsd.prog.mk +++ b/share/mk/bsd.prog.mk @@ -4,7 +4,7 @@ .include .include -.SUFFIXES: .out .o .bc .c .cc .cpp .cxx .C .m .y .l .ll .ln .s .S .asm +.include # XXX The use of COPTS in modern makefiles is discouraged. .if defined(COPTS) @@ -47,13 +47,14 @@ LDFLAGS+= -Wl,-zrelro .endif .endif -.if ${MK_PIE} != "no" # Static PIE is not yet supported/tested. -.if !defined(NO_SHARED) || ${NO_SHARED:tl} == "no" +.if ${MK_PIE} != "no" && (!defined(NO_SHARED) || ${NO_SHARED:tl} == "no") CFLAGS+= -fPIE CXXFLAGS+= -fPIE LDFLAGS+= -pie -.endif +OBJ_EXT=pieo +.else +OBJ_EXT=o .endif .if ${MK_RETPOLINE} != "no" .if ${COMPILER_FEATURES:Mretpoline} && ${LINKER_FEATURES:Mretpoline} @@ -161,7 +162,7 @@ .if defined(SRCS) -OBJS+= ${SRCS:N*.h:${OBJS_SRCS_FILTER:ts:}:S/$/.o/g} +OBJS+= ${SRCS:N*.h:${OBJS_SRCS_FILTER:ts:}:S/$/.${OBJ_EXT}/g} # LLVM bitcode / textual IR representations of the program BCOBJS+=${SRCS:N*.[hsS]:N*.asm:${OBJS_SRCS_FILTER:ts:}:S/$/.bco/g} @@ -197,10 +198,10 @@ # - the name of the object gets put into the executable symbol table instead of # the name of a variable temporary object. # - it's useful to keep objects around for crunching. -OBJS+= ${PROG}.o +OBJS+= ${PROG}.${OBJ_EXT} BCOBJS+= ${PROG}.bc LLOBJS+= ${PROG}.ll -CLEANFILES+= ${PROG}.o ${PROG}.bc ${PROG}.ll +CLEANFILES+= ${PROG}.${OBJ_EXT} ${PROG}.bc ${PROG}.ll .if target(beforelinking) beforelinking: ${OBJS} diff --git a/share/mk/bsd.progs.mk b/share/mk/bsd.progs.mk --- a/share/mk/bsd.progs.mk +++ b/share/mk/bsd.progs.mk @@ -110,7 +110,7 @@ .if !empty(_PROGS_COMMON_SRCS) _PROGS_COMMON_OBJS= ${_PROGS_COMMON_SRCS:M*.[dhly]} .if !empty(_PROGS_COMMON_SRCS:N*.[dhly]) -_PROGS_COMMON_OBJS+= ${_PROGS_COMMON_SRCS:N*.[dhly]:${OBJS_SRCS_FILTER:ts:}:S/$/.o/g} +_PROGS_COMMON_OBJS+= ${_PROGS_COMMON_SRCS:N*.[dhly]:${OBJS_SRCS_FILTER:ts:}:S/$/.${OBJ_EXT}/g} .endif .endif diff --git a/share/mk/bsd.suffixes-extra.mk b/share/mk/bsd.suffixes-extra.mk new file mode 100644 --- /dev/null +++ b/share/mk/bsd.suffixes-extra.mk @@ -0,0 +1,76 @@ +.if !target(____) +____: .NOTMAIN + +# prefer .s to a .c, remove stuff not used in the BSD libraries +# .pico used for PIC object files +# .nossppico used for NOSSP PIC object files +# .pieo used for PIE object files +.SUFFIXES: .out .o .bc .ll .pico .nossppico .pieo .S .asm .s .c .cc .cpp .cxx .C .f .y .l .ln + +PICFLAG?=-fpic +PIEFLAG?=-fpie + +.c.pico: + ${CC} ${PICFLAG} -DPIC ${SHARED_CFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.c.nossppico: + ${CC} ${PICFLAG} -DPIC ${SHARED_CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} ${CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.c.pieo: + ${CC} ${PIEFLAG} -DPIC ${SHARED_CFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.cc.pico .C.pico .cpp.pico .cxx.pico: + ${CXX} ${PICFLAG} -DPIC ${SHARED_CXXFLAGS} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET} + +.cc.nossppico .C.nossppico .cpp.nossppico .cxx.nossppico: + ${CXX} ${PICFLAG} -DPIC ${SHARED_CXXFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} ${CXXFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//:C/^-fsanitize.*$//} -c ${.IMPSRC} -o ${.TARGET} + +.cc.pieo .C.pieo .cpp.pieo .cxx.pieo: + ${CXX} ${PIEFLAG} ${SHARED_CXXFLAGS} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET} + +.f.pico: + ${FC} ${PICFLAG} -DPIC ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC} + ${CTFCONVERT_CMD} + +.f.nossppico: + ${FC} ${PICFLAG} -DPIC ${FFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//} -o ${.TARGET} -c ${.IMPSRC} + ${CTFCONVERT_CMD} + +.s.pico .s.nossppico .s.pieo: + ${CC:N${CCACHE_BIN}} -x assembler ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.asm.pico: + ${CC:N${CCACHE_BIN}} -x assembler-with-cpp ${PICFLAG} -DPIC \ + ${CFLAGS} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.asm.nossppico: + ${CC:N${CCACHE_BIN}} -x assembler-with-cpp ${PICFLAG} -DPIC \ + ${CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.asm.pieo: + ${CC:N${CCACHE_BIN}} -x assembler-with-cpp ${PIEFLAG} -DPIC \ + ${CFLAGS} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.S.pico: + ${CC:N${CCACHE_BIN}} ${PICFLAG} -DPIC ${CFLAGS} ${ACFLAGS} \ + -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.S.nossppico: + ${CC:N${CCACHE_BIN}} ${PICFLAG} -DPIC ${CFLAGS:C/^-fstack-protector.*$//:C/^-fstack-clash-protection.*$//} ${ACFLAGS} \ + -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.S.pieo: + ${CC:N${CCACHE_BIN}} ${PIEFLAG} -DPIC ${CFLAGS} ${ACFLAGS} \ + -c ${.IMPSRC} -o ${.TARGET} + ${CTFCONVERT_CMD} + +.endif # !target(____) diff --git a/share/vt/keymaps/INDEX.keymaps b/share/vt/keymaps/INDEX.keymaps --- a/share/vt/keymaps/INDEX.keymaps +++ b/share/vt/keymaps/INDEX.keymaps @@ -547,6 +547,13 @@ us.acc.kbd:pt:Estados Unidos da América (com acentos) us.acc.kbd:es:Estadounidense (con acentos) +us.intl.acc.kbd:en:United States of America International (accent keys) +us.intl.acc.kbd:da:USA international (accenttaster) +us.intl.acc.kbd:de:US-amerikanisch international (mit Akzenten) +us.intl.acc.kbd:fr:États Unis d'Amérique International (avec accents) +us.intl.acc.kbd:pt:Estados Unidos da América Internacional (com acentos) +us.intl.acc.kbd:es:Estadounidense Internacional (con acentos) + us.dvorak.kbd:en:United States of America dvorak us.dvorak.kbd:da:USA dvorak us.dvorak.kbd:de:US-amerikanisch dvorak diff --git a/share/vt/keymaps/us.intl.acc.kbd b/share/vt/keymaps/us.intl.acc.kbd new file mode 100644 index 0000000000000000000000000000000000000000..5ae189da845d63ce1db54dc27f38f4322f426f4b GIT binary patch literal 8902 zc$}q~Yk%7`6vp58Q-}?4JJ@E)jxXcRHed`|U>oDQ;UrF*HFY}M*;a1fh#x=Rz}G`M z&rvJKP7}9%vB%Dl{<`?_k*r-6kEg|W{<0E}9$ddy)OlHC^>kijGjTsZ8P2nEEb^np zjDFm@D(*}tlf2A}QC^99F6x6^%**NiR9CpA!&O~Q52wYxxFWJ*tp6R)b-~@ehvHzDr962kX= z-Apk*78en*M+m8}@@gb5B8*V_%9Eb?!F$bXwCp~H@kX~tep!}z)OI*)`dv@H3(@6cqtIuU5Ic1iB}?waXcT0olZmq z>6leUkUOsf@swnNxnhwKdJ)I%7$eA??*Z{vM=z8lggR#+#yCSjS;qOyk@I4VFl`*v zC{|~~R!ir_7(woQj)8p54wH^3xKpN4J0@-ug53EMh{q&(J#<8=6o|MTV+6S~2jVUe z#dAkgK<}5L+_V&91i7;W;u{`_azw_VGx}x>2<4l)H4qOO5jvs<5T)8NMvyyCfcPE* zITDVjfdayB#~4BGTmbP1*2)eYQ3I;0WYUf?g4{U;;vNY*fkg!|rgPAaF@kdE9Ed%V zYAPI2A)W}mk4rH|Q0_bi;wwz&EO$iVO;s{%#~4BG{1J%XFrAI%M#j`UKh&-hBRrA$fg?&G zYo$RuhUpB*ofQxd*x-R9ikzeKU)+u{g4{U<;trn3ymmx|J_#*2OEE@}J10PVLXwRR z9ckvNW{eT!&V3+0B^h$kgftP&7$eA?2S9uVL?huYAsR78kUO6N@j2eq#f9V~3XR$^xRajx zI2$dDERJR!2%jWcxh#jqo#Xv7Gg436i1l07&~$T#eRXeP1iAAk%*F4RPCRrL8DlP@ zs2yVjx${>be!!c$7&@W?%te~CV|XI84f0+A@f`_&r?50f-;6PW+&Kc`HZRMs9FY;0 zD)(9-YS0OI|w*9^NHnXLSn z7?3+}0`WoT9-Kd{)JlYLX9>&q7DkXeueo0Wn+qe1J7@ST?k$WUcM7nD`-Ry2k)>Kx z$7gqppq1Tx#a}=eVIKG7Fh9{-QzQDzz=&Rpjp+PdjY_j?)gmFz9T1Uk5ekS9hzN*; zDk)TgICqSY7J=p^n%A2jLZnnFKqZKC#|UK+XkMauz4;h23EkY zy#%$Xx2J_03lOxc zBt&w0TDY+=!n#wZa(i01u`t5AQ>Su!Hnp)Z!nl)9ckCWvV_}4G=jG0R={)w5i0JYN z>rRQJsgN`StSVvbET(N?#A)tC(o{&A0aleTaTe3IFv7U=a-aQlAX?%pzPB)f_MN=r z>nrd@YKBx))X#2N`$XtWp~UX1w=lxy&M@sSj5y7met%)aY3`K$g%PK@Gw3gjIL)1d z{=x_+clH)SNcz7b&Yiu55l-&xEsSt-XK!JIUD+eqUl?KBY4z;q$?Mr#9{w zVci+2{=x|B&M4?FjIi#E!v4aDq*u;v<%=zQjN|>Hv(Pr3R!W_OcFgr%Pk*TUxV~qu zLtO9aYrSvX*%I#GHXVU0{UJexGJUPMLawg^hEC0O)KPh^10fe$nCp}Z;h@U%obClE zblamZ__MA`r>ldG7O3A`h`O5K`g_w=>2$lR^2noOgR}7j&UkptG=!j|vKh~SXY#~c zqY(as(0k&HEp*1Cobg1?)T>ofpE_fRoUVpWSCds!AD&J9fXAsf!!qV^J~h`}6Qj2^ z<`jg+Lq~z$pU!v&sJ-jana|l60;j8S2et6%tmtf7(KOC0y(>-&kuzg~Gh?ySTDW4y al<#ySab|4b%vic=#v*6Nl=E;+SN{h>LDVb& literal 0 Hc$@va == (state->pa - dmap_phys_base + DMAP_MIN_ADDRESS)); } -static void -pmap_bootstrap_dmap(void) +void +pmap_bootstrap_dmap(vm_size_t kernlen) { + vm_paddr_t start_pa, pa; + uint64_t tcr; int i; + tcr = READ_SPECIALREG(tcr_el1); + + /* Verify that the ASID is set through TTBR0. */ + KASSERT((tcr & TCR_A1) == 0, ("pmap_bootstrap: TCR_EL1.A1 != 0")); + + if ((tcr & TCR_DS) != 0) + pmap_lpa_enabled = true; + + pmap_l1_supported = L1_BLOCKS_SUPPORTED; + + start_pa = pmap_early_vtophys(KERNBASE); + + bs_state.freemempos = KERNBASE + kernlen; + bs_state.freemempos = roundup2(bs_state.freemempos, PAGE_SIZE); + /* Fill in physmap array. */ physmap_idx = physmem_avail(physmap, nitems(physmap)); @@ -1275,6 +1292,12 @@ } cpu_tlb_flushID(); + + bs_state.dmap_valid = true; + + /* Exclude the kernel and DMAP region */ + pa = pmap_early_vtophys(bs_state.freemempos); + physmem_exclude_region(start_pa, pa - start_pa, EXFLAG_NOALLOC); } static void @@ -1305,21 +1328,11 @@ * Bootstrap the system enough to run with virtual memory. */ void -pmap_bootstrap(vm_size_t kernlen) +pmap_bootstrap(void) { vm_offset_t dpcpu, msgbufpv; vm_paddr_t start_pa, pa; - uint64_t tcr; - - tcr = READ_SPECIALREG(tcr_el1); - - /* Verify that the ASID is set through TTBR0. */ - KASSERT((tcr & TCR_A1) == 0, ("pmap_bootstrap: TCR_EL1.A1 != 0")); - - if ((tcr & TCR_DS) != 0) - pmap_lpa_enabled = true; - - pmap_l1_supported = L1_BLOCKS_SUPPORTED; + size_t largest_phys_size; /* Set this early so we can use the pagetable walking functions */ kernel_pmap_store.pm_l0 = pagetable_l0_ttbr1; @@ -1334,12 +1347,13 @@ kernel_pmap->pm_ttbr = kernel_pmap->pm_l0_paddr; kernel_pmap->pm_asid_set = &asids; - bs_state.freemempos = KERNBASE + kernlen; - bs_state.freemempos = roundup2(bs_state.freemempos, PAGE_SIZE); + /* Reserve some VA space for early BIOS/ACPI mapping */ + preinit_map_va = roundup2(bs_state.freemempos, L2_SIZE); - /* Create a direct map region early so we can use it for pa -> va */ - pmap_bootstrap_dmap(); - bs_state.dmap_valid = true; + virtual_avail = preinit_map_va + PMAP_PREINIT_MAPPING_SIZE; + virtual_avail = roundup2(virtual_avail, L1_SIZE); + virtual_end = VM_MAX_KERNEL_ADDRESS - PMAP_MAPDEV_EARLY_SIZE; + kernel_vm_end = virtual_avail; /* * We only use PXN when we know nothing will be executed from it, e.g. @@ -1347,7 +1361,28 @@ */ bs_state.table_attrs &= ~TATTR_PXN_TABLE; - start_pa = pa = pmap_early_vtophys(KERNBASE); + /* + * Find the physical memory we could use. This needs to be after we + * exclude any memory that is mapped into the DMAP region but should + * not be used by the kernel, e.g. some UEFI memory types. + */ + physmap_idx = physmem_avail(physmap, nitems(physmap)); + + /* + * Find space for early allocations. We search for the largest + * region. This is because the user may choose a large msgbuf. + * This could be smarter, e.g. to allow multiple regions to be + * used & switch to the next when one is full. + */ + largest_phys_size = 0; + for (int i = 0; i < physmap_idx; i += 2) { + if ((physmap[i + 1] - physmap[i]) > largest_phys_size) { + largest_phys_size = physmap[i + 1] - physmap[i]; + bs_state.freemempos = PHYS_TO_DMAP(physmap[i]); + } + } + + start_pa = pmap_early_vtophys(bs_state.freemempos); /* * Create the l2 tables up to VM_MAX_KERNEL_ADDRESS. We assume that the @@ -1373,19 +1408,9 @@ alloc_pages(msgbufpv, round_page(msgbufsize) / PAGE_SIZE); msgbufp = (void *)msgbufpv; - /* Reserve some VA space for early BIOS/ACPI mapping */ - preinit_map_va = roundup2(bs_state.freemempos, L2_SIZE); - - virtual_avail = preinit_map_va + PMAP_PREINIT_MAPPING_SIZE; - virtual_avail = roundup2(virtual_avail, L1_SIZE); - virtual_end = VM_MAX_KERNEL_ADDRESS - (PMAP_MAPDEV_EARLY_SIZE); - kernel_vm_end = virtual_avail; - pa = pmap_early_vtophys(bs_state.freemempos); physmem_exclude_region(start_pa, pa - start_pa, EXFLAG_NOALLOC); - - cpu_tlb_flushID(); } #if defined(KASAN) || defined(KMSAN) diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h --- a/sys/arm64/include/pmap.h +++ b/sys/arm64/include/pmap.h @@ -141,7 +141,8 @@ #define pmap_vm_page_alloc_check(m) void pmap_activate_vm(pmap_t); -void pmap_bootstrap(vm_size_t); +void pmap_bootstrap_dmap(vm_size_t); +void pmap_bootstrap(void); int pmap_change_attr(vm_offset_t va, vm_size_t size, int mode); int pmap_change_prot(vm_offset_t va, vm_size_t size, vm_prot_t prot); void pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_t pa, int mode); diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv --- a/sys/conf/files.riscv +++ b/sys/conf/files.riscv @@ -46,6 +46,7 @@ riscv/riscv/busdma_bounce.c standard riscv/riscv/busdma_machdep.c standard riscv/riscv/cache.c standard +riscv/riscv/cbo.c standard riscv/riscv/clock.c standard riscv/riscv/copyinout.S standard riscv/riscv/cpufunc_asm.S standard diff --git a/sys/contrib/edk2/Include/Library/BaseLib.h b/sys/contrib/edk2/Include/Library/BaseLib.h --- a/sys/contrib/edk2/Include/Library/BaseLib.h +++ b/sys/contrib/edk2/Include/Library/BaseLib.h @@ -152,6 +152,29 @@ #endif // defined (MDE_CPU_RISCV64) +#if defined (MDE_CPU_LOONGARCH64) +/// +/// The LoongArch architecture context buffer used by SetJump() and LongJump() +/// +typedef struct { + UINT64 S0; + UINT64 S1; + UINT64 S2; + UINT64 S3; + UINT64 S4; + UINT64 S5; + UINT64 S6; + UINT64 S7; + UINT64 S8; + UINT64 SP; + UINT64 FP; + UINT64 RA; +} BASE_LIBRARY_JUMP_BUFFER; + +#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 + +#endif // defined (MDE_CPU_LOONGARCH64) + // // String Services // diff --git a/sys/contrib/edk2/Include/Uefi/UefiBaseType.h b/sys/contrib/edk2/Include/Uefi/UefiBaseType.h --- a/sys/contrib/edk2/Include/Uefi/UefiBaseType.h +++ b/sys/contrib/edk2/Include/Uefi/UefiBaseType.h @@ -248,6 +248,13 @@ #define EFI_IMAGE_MACHINE_RISCV64 0x5064 #define EFI_IMAGE_MACHINE_RISCV128 0x5128 +/// +/// PE32+ Machine type for LoongArch 32/64 images. +/// +#define EFI_IMAGE_MACHINE_LOONGARCH32 0x6232 +#define EFI_IMAGE_MACHINE_LOONGARCH64 0x6264 + + #if defined (MDE_CPU_IA32) #define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ @@ -281,6 +288,13 @@ #define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + #elif defined (MDE_CPU_LOONGARCH64) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + ((Machine) == EFI_IMAGE_MACHINE_LOONGARCH64) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + #elif defined (MDE_CPU_EBC) /// diff --git a/sys/contrib/edk2/Include/Uefi/UefiSpec.h b/sys/contrib/edk2/Include/Uefi/UefiSpec.h --- a/sys/contrib/edk2/Include/Uefi/UefiSpec.h +++ b/sys/contrib/edk2/Include/Uefi/UefiSpec.h @@ -2203,6 +2203,7 @@ #define EFI_REMOVABLE_MEDIA_FILE_NAME_ARM L"\\EFI\\BOOT\\BOOTARM.EFI" #define EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64 L"\\EFI\\BOOT\\BOOTAA64.EFI" #define EFI_REMOVABLE_MEDIA_FILE_NAME_RISCV64 L"\\EFI\\BOOT\\BOOTRISCV64.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_LOONGARCH64 L"\\EFI\\BOOT\\BOOTLOONGARCH64.EFI" #if defined (MDE_CPU_IA32) #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 @@ -2215,7 +2216,9 @@ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64 #elif defined (MDE_CPU_RISCV64) #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_RISCV64 -#else + #elif defined (MDE_CPU_LOONGARCH64) +#define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_LOONGARCH64 + #else #error Unknown Processor Type #endif diff --git a/sys/dev/xilinx/axidma.c b/sys/dev/xilinx/axidma.c --- a/sys/dev/xilinx/axidma.c +++ b/sys/dev/xilinx/axidma.c @@ -169,6 +169,9 @@ while (chan->idx_tail != chan->idx_head) { desc = chan->descs[chan->idx_tail]; + cpu_dcache_wbinv_range((vm_offset_t)desc, + sizeof(struct axidma_desc)); + if ((desc->status & BD_STATUS_CMPLT) == 0) break; @@ -357,7 +360,8 @@ return (-1); } chan->mem_vaddr = kva_alloc(chan->mem_size); - pmap_kenter_device(chan->mem_vaddr, chan->mem_size, chan->mem_paddr); + pmap_kenter(chan->mem_vaddr, chan->mem_size, chan->mem_paddr, + VM_MEMATTR_DEFAULT); device_printf(sc->dev, "Allocated chunk %lx %lu\n", chan->mem_paddr, chan->mem_size); @@ -493,6 +497,9 @@ if (sg[i].last == 1) desc->control |= BD_CONTROL_TXEOF; + cpu_dcache_wbinv_range((vm_offset_t)desc, + sizeof(struct axidma_desc)); + tmp = chan->idx_head; atomic_add_int(&chan->descs_used_count, 1); 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 @@ -1332,7 +1332,11 @@ /* Mark the socket as using TLS offload. */ SOCK_RECVBUF_LOCK(so); - if (__predict_false(so->so_rcv.sb_tls_info != NULL)) { + if (__predict_false(so->so_rcv.sb_tls_info != NULL)) + error = EALREADY; + else if ((so->so_rcv.sb_flags & SB_SPLICED) != 0) + error = EINVAL; + if (error != 0) { SOCK_RECVBUF_UNLOCK(so); SOCK_IO_RECV_UNLOCK(so); ktls_free(tls); @@ -1432,12 +1436,16 @@ inp = so->so_pcb; INP_WLOCK(inp); SOCK_SENDBUF_LOCK(so); - if (__predict_false(so->so_snd.sb_tls_info != NULL)) { + if (__predict_false(so->so_snd.sb_tls_info != NULL)) + error = EALREADY; + else if ((so->so_snd.sb_flags & SB_SPLICED) != 0) + error = EINVAL; + if (error != 0) { SOCK_SENDBUF_UNLOCK(so); INP_WUNLOCK(inp); SOCK_IO_SEND_UNLOCK(so); ktls_free(tls); - return (EALREADY); + return (error); } so->so_snd.sb_tls_seqno = be64dec(en->rec_seq); so->so_snd.sb_tls_info = tls; diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1699,10 +1699,16 @@ uma_zfree(splice_zone, sp); return (error); } - soref(so); - so->so_splice = sp; SOCK_RECVBUF_LOCK(so); + if (so->so_rcv.sb_tls_info != NULL) { + SOCK_RECVBUF_UNLOCK(so); + SOCK_UNLOCK(so); + uma_zfree(splice_zone, sp); + return (EINVAL); + } so->so_rcv.sb_flags |= SB_SPLICED; + so->so_splice = sp; + soref(so); SOCK_RECVBUF_UNLOCK(so); SOCK_UNLOCK(so); @@ -1716,20 +1722,19 @@ error = EBUSY; if (error != 0) { SOCK_UNLOCK(so2); - SOCK_LOCK(so); - so->so_splice = NULL; - SOCK_RECVBUF_LOCK(so); - so->so_rcv.sb_flags &= ~SB_SPLICED; - SOCK_RECVBUF_UNLOCK(so); - SOCK_UNLOCK(so); - sorele(so); - uma_zfree(splice_zone, sp); + so_unsplice(so, false); return (error); } - soref(so2); - so2->so_splice_back = sp; SOCK_SENDBUF_LOCK(so2); + if (so->so_snd.sb_tls_info != NULL) { + SOCK_SENDBUF_UNLOCK(so2); + SOCK_UNLOCK(so2); + so_unsplice(so, false); + return (EINVAL); + } so2->so_snd.sb_flags |= SB_SPLICED; + so2->so_splice_back = sp; + soref(so2); mtx_lock(&sp->mtx); SOCK_SENDBUF_UNLOCK(so2); SOCK_UNLOCK(so2); @@ -1754,7 +1759,7 @@ { struct socket *so2; struct so_splice *sp; - bool drain; + bool drain, so2rele; /* * First unset SB_SPLICED and hide the splice structure so that @@ -1793,11 +1798,14 @@ SOCK_LOCK(so2); KASSERT(!SOLISTENING(so2), ("%s: so2 is listening", __func__)); SOCK_SENDBUF_LOCK(so2); - KASSERT((so2->so_snd.sb_flags & SB_SPLICED) != 0, + KASSERT(sp->state == SPLICE_INIT || + (so2->so_snd.sb_flags & SB_SPLICED) != 0, ("%s: so2 is not spliced", __func__)); - KASSERT(so2->so_splice_back == sp, + KASSERT(sp->state == SPLICE_INIT || + so2->so_splice_back == sp, ("%s: so_splice_back != sp", __func__)); so2->so_snd.sb_flags &= ~SB_SPLICED; + so2rele = so2->so_splice_back != NULL; so2->so_splice_back = NULL; SOCK_SENDBUF_UNLOCK(so2); SOCK_UNLOCK(so2); @@ -1815,6 +1823,7 @@ while (sp->state == SPLICE_CLOSING) msleep(sp, &sp->mtx, PSOCK, "unsplice", 0); break; + case SPLICE_INIT: case SPLICE_IDLE: case SPLICE_EXCEPTION: sp->state = SPLICE_CLOSED; @@ -1840,7 +1849,8 @@ CURVNET_SET(so->so_vnet); sorele(so); sowwakeup(so2); - sorele(so2); + if (so2rele) + sorele(so2); CURVNET_RESTORE(); so_splice_free(sp); return (0); diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2087,6 +2087,12 @@ hlim = 0; srcp = NULL; + if (__predict_false(IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src))) { + nd6log((LOG_DEBUG, + "icmp6_reflect: source address is unspecified\n")); + goto bad; + } + /* * If the incoming packet was addressed directly to us (i.e. unicast), * use dst as the src for the reply. diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -109,7 +109,8 @@ */ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || - IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) || + IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_cantforward); /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ if (V_ip6_log_cannot_forward && ip6_log_ratelimit()) { diff --git a/sys/riscv/include/cbo.h b/sys/riscv/include/cbo.h new file mode 100644 --- /dev/null +++ b/sys/riscv/include/cbo.h @@ -0,0 +1,33 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Ruslan Bukin + * + * 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. + */ + +#ifndef _RISCV_CBO_H_ +#define _RISCV_CBO_H_ + +void cbo_zicbom_setup_cache(int cbom_block_size); + +#endif /* _RISCV_CBO_H_ */ diff --git a/sys/riscv/include/cpu.h b/sys/riscv/include/cpu.h --- a/sys/riscv/include/cpu.h +++ b/sys/riscv/include/cpu.h @@ -80,6 +80,7 @@ /* SiFive marchid values */ #define MARCHID_SIFIVE_U7 MARCHID_COMMERCIAL(7) +#define MARCHID_SIFIVE_P5 MARCHID_COMMERCIAL(8) /* * MMU virtual-addressing modes. Support for each level implies the previous, diff --git a/sys/riscv/riscv/cbo.c b/sys/riscv/riscv/cbo.c new file mode 100644 --- /dev/null +++ b/sys/riscv/riscv/cbo.c @@ -0,0 +1,104 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Ruslan Bukin + * + * 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. + */ + +/* Cache Block Operations. */ + +#include +#include + +#include + +static void +cbo_zicbom_cpu_dcache_wbinv_range(vm_offset_t va, vm_size_t len) +{ + vm_offset_t addr; + + /* + * A flush operation atomically performs a clean operation followed by + * an invalidate operation. + */ + + va &= ~(dcache_line_size - 1); + for (addr = va; addr < va + len; addr += dcache_line_size) + __asm __volatile(".option push; .option arch, +zicbom\n" + "cbo.flush (%0); .option pop\n" :: "r"(addr)); +} + +static void +cbo_zicbom_cpu_dcache_inv_range(vm_offset_t va, vm_size_t len) +{ + vm_offset_t addr; + + /* + * An invalidate operation makes data from store operations performed by + * a set of non-coherent agents visible to the set of coherent agents at + * a point common to both sets by deallocating all copies of a cache + * block from the set of coherent caches up to that point. + */ + + va &= ~(dcache_line_size - 1); + for (addr = va; addr < va + len; addr += dcache_line_size) + __asm __volatile(".option push; .option arch, +zicbom\n" + "cbo.inval (%0); .option pop\n" :: "r"(addr)); +} + +static void +cbo_zicbom_cpu_dcache_wb_range(vm_offset_t va, vm_size_t len) +{ + vm_offset_t addr; + + /* + * A clean operation makes data from store operations performed by the + * set of coherent agents visible to a set of non-coherent agents at a + * point common to both sets by performing a write transfer of a copy of + * a cache block to that point provided a coherent agent performed a + * store operation that modified the data in the cache block since the + * previous invalidate, clean, or flush operation on the cache block. + */ + + va &= ~(dcache_line_size - 1); + for (addr = va; addr < va + len; addr += dcache_line_size) + __asm __volatile(".option push; .option arch, +zicbom\n" + "cbo.clean (%0); .option pop\n" :: "r"(addr)); +} + +void +cbo_zicbom_setup_cache(int cbom_block_size) +{ + struct riscv_cache_ops zicbom_ops; + + if (cbom_block_size <= 0 || !powerof2(cbom_block_size)) { + printf("Zicbom: could not initialise (invalid cache line %d)\n", + cbom_block_size); + return; + } + + zicbom_ops.dcache_wbinv_range = cbo_zicbom_cpu_dcache_wbinv_range; + zicbom_ops.dcache_inv_range = cbo_zicbom_cpu_dcache_inv_range; + zicbom_ops.dcache_wb_range = cbo_zicbom_cpu_dcache_wb_range; + riscv_cache_install_hooks(&zicbom_ops, cbom_block_size); +} diff --git a/sys/riscv/riscv/identcpu.c b/sys/riscv/riscv/identcpu.c --- a/sys/riscv/riscv/identcpu.c +++ b/sys/riscv/riscv/identcpu.c @@ -53,6 +53,7 @@ #include #include #include +#include #ifdef FDT #include @@ -78,6 +79,11 @@ bool __read_frequently has_sscofpmf; bool has_svpbmt; +/* Z-extensions support. */ +bool has_zicbom; +bool has_zicboz; +bool has_zicbop; + struct cpu_desc { const char *cpu_mvendor_name; const char *cpu_march_name; @@ -89,6 +95,12 @@ #define SV_SVPBMT (1 << 2) #define SV_SVINVAL (1 << 3) #define SV_SSCOFPMF (1 << 4) + u_int z_extensions; /* Multi-letter extensions. */ +#define Z_ZICBOM (1 << 0) +#define Z_ZICBOZ (1 << 1) +#define Z_ZICBOP (1 << 2) + int cbom_block_size; + int cboz_block_size; }; struct cpu_desc cpu_desc[MAXCPU]; @@ -114,6 +126,7 @@ static const struct marchid_entry sifive_marchids[] = { { MARCHID_SIFIVE_U7, "6/7/P200/X200-Series Processor" }, + { MARCHID_SIFIVE_P5, "P550/P650 Processor" }, MARCHID_END }; @@ -196,11 +209,24 @@ static __inline int parse_ext_z(struct cpu_desc *desc __unused, char *isa, int idx, int len) { +#define CHECK_Z_EXT(str, flag) \ + do { \ + if (strncmp(&isa[idx], (str), \ + MIN(strlen(str), len - idx)) == 0) { \ + desc->z_extensions |= flag; \ + return (idx + strlen(str)); \ + } \ + } while (0) + + /* Check for known/supported extensions. */ + CHECK_Z_EXT("zicbom", Z_ZICBOM); + CHECK_Z_EXT("zicboz", Z_ZICBOZ); + CHECK_Z_EXT("zicbop", Z_ZICBOP); + +#undef CHECK_Z_EXT /* * Proceed to the next multi-letter extension or the end of the * string. - * - * TODO: parse some of these. */ while (isa[idx] != '_' && idx < len) { idx++; @@ -321,6 +347,22 @@ } } +static void +parse_cbo_fdt(struct cpu_desc *desc, phandle_t node) +{ + int error; + + error = OF_getencprop(node, "riscv,cbom-block-size", + &desc->cbom_block_size, sizeof(desc->cbom_block_size)); + if (error == -1) + desc->cbom_block_size = 0; + + error = OF_getencprop(node, "riscv,cboz-block-size", + &desc->cboz_block_size, sizeof(desc->cboz_block_size)); + if (error == -1) + desc->cboz_block_size = 0; +} + static void identify_cpu_features_fdt(u_int cpu, struct cpu_desc *desc) { @@ -372,6 +414,9 @@ /* Check MMU features. */ parse_mmu_fdt(desc, node); + /* Cache-block operations (CBO). */ + parse_cbo_fdt(desc, node); + /* We are done. */ break; } @@ -422,6 +467,11 @@ UPDATE_CAP(has_sscofpmf, (desc->smode_extensions & SV_SSCOFPMF) != 0); UPDATE_CAP(has_svpbmt, (desc->smode_extensions & SV_SVPBMT) != 0); + /* Z extension support. */ + UPDATE_CAP(has_zicbom, (desc->z_extensions & Z_ZICBOM) != 0); + UPDATE_CAP(has_zicboz, (desc->z_extensions & Z_ZICBOZ) != 0); + UPDATE_CAP(has_zicbop, (desc->z_extensions & Z_ZICBOP) != 0); + #undef UPDATE_CAP } @@ -506,6 +556,9 @@ update_global_capabilities(cpu, desc); handle_cpu_quirks(cpu, desc); + + if (has_zicbom && cpu == 0) + cbo_zicbom_setup_cache(desc->cbom_block_size); } void diff --git a/tools/tools/git/ghpr/ghpr-init.sh b/tools/tools/git/ghpr/ghpr-init.sh --- a/tools/tools/git/ghpr/ghpr-init.sh +++ b/tools/tools/git/ghpr/ghpr-init.sh @@ -16,12 +16,14 @@ # Bail if the branch already exists else if git rev-parse --verify ${BRANCH} > /dev/null 2>&1; then - echo "Branch ${BRANCH} already exists, skipping creation" + echo "Branch ${BRANCH} already exists, skipping creation, but rebasing to ${base}" + git rebase ${base} ${BRANCH} else # Create the branch and tag it as the one we're using for opabinia merging. + echo "Creating ${BRANCH} from ${base} to land changes" git checkout -b ${BRANCH} ${base} || die "Can't create ${BRANCH}" fi fi -git config --add --type bool branch.${BRANCH}.opabinia true || die "Can't annotate" -git config --add branch.${BRANCH}.opabinia.base ${base} || die "Can't annotate" +git config set --type bool --all branch.${BRANCH}.opabinia true || die "Can't annotate" +git config set --all branch.${BRANCH}.opabinia.base "${base}" || die "Can't annotate" diff --git a/tools/tools/git/ghpr/ghpr-push.sh b/tools/tools/git/ghpr/ghpr-push.sh --- a/tools/tools/git/ghpr/ghpr-push.sh +++ b/tools/tools/git/ghpr/ghpr-push.sh @@ -42,6 +42,7 @@ for pr in $(git config --get-all branch.${staging}.opabinia.prs); do if ! $do_pr_branch_push; then gh pr edit $pr --add-label merged + gh pr close $pr --comment "ghpr helper script closed this after push to source of truth." fi git branch -D PR-${pr} git config --remove-section branch.${staging}.opabinia.${pr}