Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150613346
D40193.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D40193.id.diff
View Options
diff --git a/sys/conf/automation.mk b/sys/conf/automation.mk
new file mode 100644
--- /dev/null
+++ b/sys/conf/automation.mk
@@ -0,0 +1,74 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright (c) 2023 Hans Petter Selasky <hselasky@freebsd.org>
+#
+# 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.
+#
+# $FreeBSD$
+
+AUTOMATION_BASE=automation
+
+CLEANFILES+=\
+ ${AUTOMATION_BASE}.txt \
+ ${AUTOMATION_BASE}.o
+
+DEPENDOBJS+=\
+ ${AUTOMATION_BASE}.txt \
+ ${AUTOMATION_BASE}.o
+
+AUTOMATION_HEADER=(\
+ echo "/*" ; \
+ echo " * This file was automatically generated. " ; \
+ echo " * Please do not edit. " ; \
+ echo " */ " ; \
+ echo "" ; \
+ echo "\#include <sys/cdefs.h>" ; \
+ echo "\#include <sys/linker_set.h>" ; \
+ echo "" ; \
+ echo "struct sysinit;" ; \
+ echo "" ; \
+ echo "\#define SYSINIT(var) \\" ; \
+ echo "extern struct sysinit var; \\" ; \
+ echo "DATA_WSET(sysinit_set,var)" ; \
+ echo "" ; \
+ echo "\#define SYSUNINIT(var) \\" ; \
+ echo "extern struct sysinit var; \\" ; \
+ echo "DATA_WSET(sysuninit_set,var)" ; \
+ echo "" \
+)
+
+# Define hint to make global variables uniq
+CFLAGS+= \
+ -DAUTOMATION_HINT=${.TARGET:C/.*\///g:S/./_/g:S/-/_/g}
+
+${AUTOMATION_BASE}.o: ${OBJS:N${AUTOMATION_BASE}_sysinit.o}
+ @${LD} -T /dev/null -o ${.TARGET} -r ${.ALLSRC}
+
+${AUTOMATION_BASE}.txt: ${AUTOMATION_BASE}.o
+ @${OBJCOPY} -j set_automation -O binary ${.ALLSRC} ${.TARGET}
+
+${AUTOMATION_BASE}_sysinit.c: ${AUTOMATION_BASE}.txt
+ @ ${AUTOMATION_HEADER} > ${.TARGET}
+ @cat ${AUTOMATION_BASE}.txt | tr '\0' '\n' | grep -E "^sysinit " | sort -f | ${AWK} '{print "SYSINIT(" $$4 "); /* " $$2 " " $$3 " */"}' >> ${.TARGET}
+ @echo "" >> ${.TARGET}
+ @cat ${AUTOMATION_BASE}.txt | tr '\0' '\n' | grep -E "^sysuninit " | sort -fr | ${AWK} '{print "SYSUNINIT(" $$4 "); /* " $$2 " " $$3 " */"}' >> ${.TARGET}
diff --git a/sys/conf/kern.mk b/sys/conf/kern.mk
--- a/sys/conf/kern.mk
+++ b/sys/conf/kern.mk
@@ -332,6 +332,9 @@
LD_EMULATION_riscv64= elf64lriscv
LD_EMULATION=${LD_EMULATION_${MACHINE_ARCH}}
+# Kernel automation
+.include "automation.mk"
+
#
# Autogenerated files must be located in the current object directory
# and not the one belonging to the parent build. This prevents kernel
diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk
--- a/sys/conf/kern.post.mk
+++ b/sys/conf/kern.post.mk
@@ -8,6 +8,11 @@
# should be defined in the kern.pre.mk so that port makefiles can
# override or augment them.
+# Kernel automation
+CFILES+= automation_sysinit.c
+OBJS+= automation_sysinit.o
+CLEAN+= automation_sysinit.c
+
.if defined(DTS) || defined(DTSO) || defined(FDT_DTS_FILE)
.include "dtb.build.mk"
diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk
--- a/sys/conf/kmod.mk
+++ b/sys/conf/kmod.mk
@@ -190,6 +190,10 @@
CTFFLAGS+= -g
.endif
+# Module automation
+SRCS+= automation_sysinit.c
+CLEANFILES+= automation_sysinit.c
+
.if defined(FIRMWS)
${KMOD:S/$/.c/}: ${SYSDIR}/tools/fw_stub.awk
${AWK} -f ${SYSDIR}/tools/fw_stub.awk ${FIRMWS} -m${KMOD} -c${KMOD:S/$/.c/g} \
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -160,8 +160,26 @@
* If we want to register new sysinit types, add them to newsysinit.
*/
SET_DECLARE(sysinit_set, struct sysinit);
-struct sysinit **sysinit, **sysinit_end;
-struct sysinit **newsysinit, **newsysinit_end;
+static struct sysinit **sysinit, **sysinit_end;
+static struct sysinit **newsysinit, **newsysinit_end;
+
+/*
+ * Compare two sysinit structures.
+ */
+static int
+sysinit_compare(struct sysinit **ppa, struct sysinit **ppb)
+{
+ if (ppa[0][0].subsystem > ppb[0][0].subsystem)
+ return (1);
+ else if (ppa[0][0].subsystem < ppb[0][0].subsystem)
+ return (-1);
+ else if (ppa[0][0].order > ppb[0][0].order)
+ return (1);
+ else if (ppa[0][0].order < ppb[0][0].order)
+ return (-1);
+ else
+ return (0);
+}
/*
* Merge a new sysinit set into the current set, reallocating it if
@@ -171,8 +189,10 @@
sysinit_add(struct sysinit **set, struct sysinit **set_end)
{
struct sysinit **newset;
- struct sysinit **sipp;
- struct sysinit **xipp;
+ struct sysinit **ppa;
+ struct sysinit **ppb;
+ struct sysinit **ppc;
+ struct sysinit **end;
int count;
count = set_end - set;
@@ -180,24 +200,73 @@
count += newsysinit_end - newsysinit;
else
count += sysinit_end - sysinit;
- newset = malloc(count * sizeof(*sipp), M_TEMP, M_NOWAIT);
+ newset = malloc(count * sizeof(*newset), M_TEMP, M_NOWAIT);
if (newset == NULL)
- panic("cannot malloc for sysinit");
- xipp = newset;
- if (newsysinit)
- for (sipp = newsysinit; sipp < newsysinit_end; sipp++)
- *xipp++ = *sipp;
- else
- for (sipp = sysinit; sipp < sysinit_end; sipp++)
- *xipp++ = *sipp;
- for (sipp = set; sipp < set_end; sipp++)
- *xipp++ = *sipp;
- if (newsysinit)
- free(newsysinit, M_TEMP);
+ panic("Cannot allocate memory for sysinit_add()");
+
+ ppa = set;
+ ppb = newsysinit ? newsysinit : sysinit;
+ end = newsysinit ? newsysinit_end : sysinit_end;
+ ppc = newset;
+
+ /* Merge two sorted lists by picking the lowest element first. */
+
+ while (ppa != set_end && ppb != end) {
+ switch (sysinit_compare(ppa, ppb)) {
+ case -1:
+ *ppc++ = *ppa++;
+ break;
+ case 0:
+ *ppc++ = *ppa++;
+ *ppc++ = *ppb++;
+ break;
+ default:
+ *ppc++ = *ppb++;
+ break;
+ }
+ }
+
+ while (ppa != set_end)
+ *ppc++ = *ppa++;
+ while (ppb != end)
+ *ppc++ = *ppb++;
+
+ free(newsysinit, M_TEMP);
newsysinit = newset;
newsysinit_end = newset + count;
}
+/*
+ * Sort a sysinit or sysuninit set. The entries should already have
+ * been sorted, and this function is basically a O(N) dummy operation!
+ */
+void
+sysinit_sort(struct sysinit **start, struct sysinit **stop)
+{
+ struct sysinit **sipp, **xipp, *save;
+
+ /* check for empty set */
+ if (start == stop)
+ return;
+
+ TSENTER2("insertionsort");
+
+ /*
+ * Sort all entries by their subsystem (primary key) and order
+ * (secondary key).
+ */
+ for (sipp = start + 1; sipp != stop; sipp++) {
+ for (xipp = sipp; xipp != start &&
+ sysinit_compare(xipp - 1, xipp) > 0; xipp--) {
+ save = *(xipp - 1);
+ *(xipp - 1) = *xipp;
+ *xipp = save;
+ }
+ }
+
+ TSEXIT2("insertionsort");
+}
+
#if defined (DDB) && defined(VERBOSE_SYSINIT)
static const char *
symbol_name(vm_offset_t va, db_strategy_t strategy)
@@ -232,8 +301,6 @@
{
struct sysinit **sipp; /* system initialization*/
- struct sysinit **xipp; /* interior loop of sort*/
- struct sysinit *save; /* bubble*/
int last;
#if defined(VERBOSE_SYSINIT)
@@ -251,23 +318,7 @@
}
restart:
- /*
- * Perform a bubble sort of the system initialization objects by
- * their subsystem (primary key) and order (secondary key).
- */
- TSENTER2("bubblesort");
- for (sipp = sysinit; sipp < sysinit_end; sipp++) {
- for (xipp = sipp + 1; xipp < sysinit_end; xipp++) {
- if ((*sipp)->subsystem < (*xipp)->subsystem ||
- ((*sipp)->subsystem == (*xipp)->subsystem &&
- (*sipp)->order <= (*xipp)->order))
- continue; /* skip*/
- save = *sipp;
- *sipp = *xipp;
- *xipp = save;
- }
- }
- TSEXIT2("bubblesort");
+ sysinit_sort(sysinit, sysinit_end);
last = SI_SUB_COPYRIGHT;
#if defined(VERBOSE_SYSINIT)
@@ -326,6 +377,8 @@
/* Check off the one we're just done */
last = (*sipp)->subsystem;
(*sipp)->subsystem = SI_SUB_DONE;
+ /* Clear the order to avoid re-sorting the already executed sysinits */
+ (*sipp)->order = SI_ORDER_FIRST;
/* Check if we've installed more sysinit items via KLD */
if (newsysinit != NULL) {
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -195,8 +195,8 @@
static void
linker_file_sysinit(linker_file_t lf)
{
- struct sysinit **start, **stop, **sipp, **xipp, *save;
- int last;
+ struct sysinit **start, **stop, **sipp;
+ uint32_t last;
KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
lf->filename));
@@ -205,24 +205,8 @@
if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
return;
- /*
- * Perform a bubble sort of the system initialization objects by
- * their subsystem (primary key) and order (secondary key).
- *
- * Since some things care about execution order, this is the operation
- * which ensures continued function.
- */
- for (sipp = start; sipp < stop; sipp++) {
- for (xipp = sipp + 1; xipp < stop; xipp++) {
- if ((*sipp)->subsystem < (*xipp)->subsystem ||
- ((*sipp)->subsystem == (*xipp)->subsystem &&
- (*sipp)->order <= (*xipp)->order))
- continue; /* skip */
- save = *sipp;
- *sipp = *xipp;
- *xipp = save;
- }
- }
+
+ sysinit_sort(start, stop);
/*
* Traverse the (now) ordered list of system initialization tasks.
@@ -250,8 +234,8 @@
static void
linker_file_sysuninit(linker_file_t lf)
{
- struct sysinit **start, **stop, **sipp, **xipp, *save;
- int last;
+ struct sysinit **start, **stop, **sipp;
+ uint32_t last;
KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
lf->filename));
@@ -262,24 +246,7 @@
NULL) != 0)
return;
- /*
- * Perform a reverse bubble sort of the system initialization objects
- * by their subsystem (primary key) and order (secondary key).
- *
- * Since some things care about execution order, this is the operation
- * which ensures continued function.
- */
- for (sipp = start; sipp < stop; sipp++) {
- for (xipp = sipp + 1; xipp < stop; xipp++) {
- if ((*sipp)->subsystem > (*xipp)->subsystem ||
- ((*sipp)->subsystem == (*xipp)->subsystem &&
- (*sipp)->order >= (*xipp)->order))
- continue; /* skip */
- save = *sipp;
- *sipp = *xipp;
- *xipp = save;
- }
- }
+ sysinit_sort(start, stop);
/*
* Traverse the (now) ordered list of system initialization tasks.
@@ -289,12 +256,12 @@
mtx_lock(&Giant);
last = SI_SUB_DUMMY;
for (sipp = start; sipp < stop; sipp++) {
- if ((*sipp)->subsystem == SI_SUB_DUMMY)
+ if ((*sipp)->subsystem == (SI_SUB_DUMMY ^ SI_SUB_LAST))
continue; /* skip dummy task(s) */
if ((*sipp)->subsystem > last)
BOOTTRACE("%s: sysuninit 0x%7x", lf->filename,
- (*sipp)->subsystem);
+ (*sipp)->subsystem ^ SI_SUB_LAST);
/* Call function */
(*((*sipp)->func)) ((*sipp)->udata);
diff --git a/sys/sys/automation.h b/sys/sys/automation.h
new file mode 100644
--- /dev/null
+++ b/sys/sys/automation.h
@@ -0,0 +1,74 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2023 Hans Petter Selasky <hselasky@FreeBSD.org>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_AUTOMATION_H_
+#define _SYS_AUTOMATION_H_
+
+#include <sys/cdefs.h>
+
+__WEAK(__start_set_automation);
+__WEAK(__stop_set_automation);
+
+#define __EXPORT_AUTOMATION(id,...) \
+static const id __section("set_automation") __used __aligned(1) = { __VA_ARGS__ }
+
+/*
+ * The EXPORT_AUTOMATION() macro stores the C-string after the first
+ * identifier argument, into a special automation section. The strings
+ * in this section are later parsed by "sys/conf/automation.mk" .
+ *
+ * All NUL-characters are converted into newline characters.
+ *
+ * There is one command per line.
+ *
+ * Typical format:
+ * "command<space>argument(s)\n".
+ *
+ * Example:
+ * EXPORT_AUTOMATION(char xxx[], "sysinit global_variable");
+ */
+#define EXPORT_AUTOMATION(...) \
+ __EXPORT_AUTOMATION(__VA_ARGS__)
+
+#define EXPORT_HEX_DIGIT(x) \
+ (((x) < 10) ? ('0' + (x)) : ('a' + (x) - 10))
+
+#define EXPORT_HEX_U8(x) \
+ EXPORT_HEX_DIGIT(((x) >> 4) & 0xF), \
+ EXPORT_HEX_DIGIT(((x) >> 0) & 0xF)
+
+#define EXPORT_HEX_U16(x) \
+ EXPORT_HEX_U8((x) >> 8), \
+ EXPORT_HEX_U8((x) >> 0)
+
+#define EXPORT_HEX_U32(x) \
+ EXPORT_HEX_U16((x) >> 16), \
+ EXPORT_HEX_U16((x) >> 0)
+
+#endif /* _SYS_AUTOMATION_H_ */
diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h
--- a/sys/sys/kernel.h
+++ b/sys/sys/kernel.h
@@ -57,6 +57,8 @@
/* for timestamping SYSINITs; other files may assume this is included here */
#include <sys/tslog.h>
+#include <sys/automation.h>
+
/* Global variables for the kernel. */
/* 1.1 */
@@ -225,6 +227,36 @@
const void *udata; /* multiplexer/argument */
};
+/*
+ * Helper macros for automating sysinits.
+ *
+ * The __SI_EXPORT() macro builds a NUL terminated ASCII string, being
+ * parsed by automation.mk later on.
+ */
+#define __SI_EXPORT(type, sub, order, var, uniq) \
+ _Static_assert((sub) >= 0 && (sub) <= SI_SUB_LAST, "Subsystem is out of range"); \
+ _Static_assert((order) >= 0 && (order) <= SI_ORDER_ANY, "Order is out of range"); \
+ EXPORT_AUTOMATION(struct { \
+ char a[sizeof(#type) - 1]; \
+ char b[1]; \
+ char c[11]; \
+ char d[11]; \
+ char e[sizeof(#type "_" #var "_" #uniq)]; \
+ } export_##type##_##var, \
+ { #type }, \
+ { ' ' }, \
+ {'0','x',EXPORT_HEX_U32(sub),' '}, \
+ {'0','x',EXPORT_HEX_U32(order),' '}, \
+ { #type "_" #var "_" #uniq }); \
+ extern struct sysinit type##_##var##_##uniq; \
+ struct sysinit type##_##var##_##uniq
+
+#define _SI_EXPORT(...) \
+ __SI_EXPORT(__VA_ARGS__)
+
+#define SI_EXPORT(...) \
+ _SI_EXPORT(__VA_ARGS__, AUTOMATION_HINT)
+
/*
* Default: no special processing
*
@@ -252,51 +284,53 @@
(x->func)(x->data);
TSRAW(curthread, TS_EXIT, "SYSINIT", x->name);
}
-#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
- static struct sysinit_tslog uniquifier ## _sys_init_tslog = { \
+#define C_SYSINIT(uniq, subsystem, order, func, arg) \
+ static const struct sysinit_tslog sysinit_tslog_##uniq = \
+ { \
func, \
- (ident), \
- #uniquifier \
+ arg, \
+ #uniq \
}; \
- static struct sysinit uniquifier ## _sys_init = { \
+ SI_EXPORT(sysinit, subsystem, order, uniq) = \
+ { \
subsystem, \
order, \
sysinit_tslog_shim, \
- &uniquifier ## _sys_init_tslog \
- }; \
- DATA_WSET(sysinit_set,uniquifier ## _sys_init)
+ &sysinit_tslog_##uniq, \
+ }
#else
-#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
- static struct sysinit uniquifier ## _sys_init = { \
+#define C_SYSINIT(uniq, subsystem, order, func, arg) \
+ SI_EXPORT(sysinit, subsystem, order, uniq) = \
+ { \
subsystem, \
order, \
func, \
- (ident) \
- }; \
- DATA_WSET(sysinit_set,uniquifier ## _sys_init)
+ arg \
+ }
#endif
-#define SYSINIT(uniquifier, subsystem, order, func, ident) \
+#define SYSINIT(uniquifier, subsystem, order, func, arg) \
C_SYSINIT(uniquifier, subsystem, order, \
- (sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)(ident))
+ (sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)(arg))
/*
* Called on module unload: no special processing
*/
-#define C_SYSUNINIT(uniquifier, subsystem, order, func, ident) \
- static struct sysinit uniquifier ## _sys_uninit = { \
- subsystem, \
- order, \
+#define C_SYSUNINIT(uniq, subsystem, order, func, arg) \
+ SI_EXPORT(sysuninit, subsystem, order, uniq) = \
+ { \
+ subsystem ^ SI_SUB_LAST, \
+ order ^ SI_ORDER_ANY, \
func, \
- (ident) \
- }; \
- DATA_WSET(sysuninit_set,uniquifier ## _sys_uninit)
+ arg \
+ }
-#define SYSUNINIT(uniquifier, subsystem, order, func, ident) \
+#define SYSUNINIT(uniquifier, subsystem, order, func, arg) \
C_SYSUNINIT(uniquifier, subsystem, order, \
- (sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)(ident))
+ (sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)(arg))
void sysinit_add(struct sysinit **set, struct sysinit **set_end);
+void sysinit_sort(struct sysinit **set, struct sysinit **set_end);
#ifdef _KERNEL
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 7:48 PM (16 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30776225
Default Alt Text
D40193.id.diff (17 KB)
Attached To
Mode
D40193: kernel: Add automation to sort all constructors and destructors at compile time.
Attached
Detach File
Event Timeline
Log In to Comment