Page MenuHomeFreeBSD

D40193.id.diff
No OneTemporary

D40193.id.diff

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

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)

Event Timeline