Module Name: src
Committed By: thorpej
Date: Tue Aug 3 15:00:15 UTC 2021
Modified Files:
src/sys/kern [thorpej-cfargs2]: subr_autoconf.c
src/sys/sys [thorpej-cfargs2]: device.h
Log Message:
Address concerns about limited compile-time type checking with the
tag-value mechanism of specifying arguments to config_search(),
config_found(), and config_attach() by replacing the tag-value scheme
with a "struct cfargs", a pointer to which is passed to the aforementioned
functions instead.
The structure has a version field to allow for future ABI versioning
flexibility. The external structure is canononicalized internally
before use.
To ease the initialization of this structure, use a variadic preprocessor
macro, CFARGS(), to construct an anonymous "struct cfargs" inline, the
address of which is passed to the target function. A CFARGS_NONE macro
provides a symbolic stand-in for when the caller doesn't want to pass
arguments (currently expands to NULL and is handled during canonicalization).
To generate a diff of this commit:
cvs rdiff -u -r1.288 -r1.288.2.1 src/sys/kern/subr_autoconf.c
cvs rdiff -u -r1.171 -r1.171.2.1 src/sys/sys/device.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/subr_autoconf.c
diff -u src/sys/kern/subr_autoconf.c:1.288 src/sys/kern/subr_autoconf.c:1.288.2.1
--- src/sys/kern/subr_autoconf.c:1.288 Mon Jun 14 08:55:49 2021
+++ src/sys/kern/subr_autoconf.c Tue Aug 3 15:00:15 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_autoconf.c,v 1.288 2021/06/14 08:55:49 skrll Exp $ */
+/* $NetBSD: subr_autoconf.c,v 1.288.2.1 2021/08/03 15:00:15 thorpej Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -76,10 +76,8 @@
* @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
*/
-#define __SUBR_AUTOCONF_PRIVATE /* see <sys/device.h> */
-
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.288 2021/06/14 08:55:49 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.288.2.1 2021/08/03 15:00:15 thorpej Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@@ -168,6 +166,20 @@ struct alldevs_foray {
struct devicelist af_garbage;
};
+/*
+ * Internal version of the cfargs structure; all versions are
+ * canonicalized to this.
+ */
+struct cfargs_internal {
+ union {
+ cfsubmatch_t submatch;/* submatch function (direct config) */
+ cfsearch_t search; /* search function (indirect config) */
+ };
+ const char * iattr; /* interface attribute */
+ const int * locators; /* locators array */
+ devhandle_t devhandle; /* devhandle_t (by value) */
+};
+
static char *number(char *, int);
static void mapply(struct matchinfo *, cfdata_t);
static void config_devdelete(device_t);
@@ -177,6 +189,8 @@ static void config_devlink(device_t);
static void config_alldevs_enter(struct alldevs_foray *);
static void config_alldevs_exit(struct alldevs_foray *);
static void config_add_attrib_dict(device_t);
+static device_t config_attach_internal(device_t, cfdata_t, void *,
+ cfprint_t, const struct cfargs_internal *);
static void config_collect_garbage(struct devicelist *);
static void config_dump_garbage(struct devicelist *);
@@ -1068,65 +1082,37 @@ config_probe(device_t parent, cfdata_t c
return config_match(parent, cf, aux);
}
-static void
-config_get_cfargs(cfarg_t tag,
- cfsubmatch_t *fnp, /* output */
- const char **ifattrp, /* output */
- const int **locsp, /* output */
- devhandle_t *handlep, /* output */
- va_list ap)
-{
- cfsubmatch_t fn = NULL;
- const char *ifattr = NULL;
- const int *locs = NULL;
- devhandle_t handle;
-
- devhandle_invalidate(&handle);
-
- while (tag != CFARG_EOL) {
- switch (tag) {
- /*
- * CFARG_SUBMATCH and CFARG_SEARCH are synonyms, but this
- * is merely an implementation detail. They are distinct
- * from the caller's point of view.
- */
- case CFARG_SUBMATCH:
- case CFARG_SEARCH:
- /* Only allow one function to be specified. */
- if (fn != NULL) {
- panic("%s: caller specified both "
- "SUBMATCH and SEARCH", __func__);
- }
- fn = va_arg(ap, cfsubmatch_t);
- break;
-
- case CFARG_IATTR:
- ifattr = va_arg(ap, const char *);
- break;
+static struct cfargs_internal *
+cfargs_canonicalize(const struct cfargs * const cfargs,
+ struct cfargs_internal * const store)
+{
+ struct cfargs_internal *args = store;
- case CFARG_LOCATORS:
- locs = va_arg(ap, const int *);
- break;
+ memset(args, 0, sizeof(*args));
- case CFARG_DEVHANDLE:
- handle = va_arg(ap, devhandle_t);
- break;
+ /* If none specified, are all-NULL pointers are good. */
+ if (cfargs == NULL) {
+ return args;
+ }
- default:
- panic("%s: unknown cfarg tag: %d\n",
- __func__, tag);
- }
- tag = va_arg(ap, cfarg_t);
+ /*
+ * submatch and search are mutually-exclusive.
+ */
+ if (cfargs->submatch != NULL && cfargs->search != NULL) {
+ panic("cfargs_canonicalize: submatch and search are "
+ "mutually-exclusive");
}
+ if (cfargs->submatch != NULL) {
+ args->submatch = cfargs->submatch;
+ } else if (cfargs->search != NULL) {
+ args->search = cfargs->search;
+ }
+
+ args->iattr = cfargs->iattr;
+ args->locators = cfargs->locators;
+ args->devhandle = cfargs->devhandle;
- if (fnp != NULL)
- *fnp = fn;
- if (ifattrp != NULL)
- *ifattrp = ifattr;
- if (locsp != NULL)
- *locsp = locs;
- if (handlep != NULL)
- *handlep = handle;
+ return args;
}
/*
@@ -1140,25 +1126,23 @@ config_get_cfargs(cfarg_t tag,
* an arbitrary function to all potential children (its return value
* can be ignored).
*/
-cfdata_t
-config_vsearch(device_t parent, void *aux, cfarg_t tag, va_list ap)
+static cfdata_t
+config_search_internal(device_t parent, void *aux,
+ const struct cfargs_internal * const args)
{
- cfsubmatch_t fn;
- const char *ifattr;
- const int *locs;
struct cftable *ct;
cfdata_t cf;
struct matchinfo m;
- config_get_cfargs(tag, &fn, &ifattr, &locs, NULL, ap);
-
KASSERT(config_initialized);
- KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
- KASSERT(ifattr || cfdriver_iattr_count(parent->dv_cfdriver) < 2);
+ KASSERT(!args->iattr ||
+ cfdriver_get_iattr(parent->dv_cfdriver, args->iattr));
+ KASSERT(args->iattr ||
+ cfdriver_iattr_count(parent->dv_cfdriver) < 2);
- m.fn = fn;
+ m.fn = args->submatch; /* N.B. union */
m.parent = parent;
- m.locs = locs;
+ m.locs = args->locators;
m.aux = aux;
m.match = NULL;
m.pri = 0;
@@ -1186,7 +1170,8 @@ config_vsearch(device_t parent, void *au
* consider only children which attach to
* that attribute.
*/
- if (ifattr && !STREQ(ifattr, cfdata_ifattr(cf)))
+ if (args->iattr != NULL &&
+ !STREQ(args->iattr, cfdata_ifattr(cf)))
continue;
if (cfparent_match(parent, cf->cf_pspec))
@@ -1197,14 +1182,13 @@ config_vsearch(device_t parent, void *au
}
cfdata_t
-config_search(device_t parent, void *aux, cfarg_t tag, ...)
+config_search(device_t parent, void *aux, const struct cfargs *cfargs)
{
cfdata_t cf;
- va_list ap;
+ struct cfargs_internal store;
- va_start(ap, tag);
- cf = config_vsearch(parent, aux, tag, ap);
- va_end(ap);
+ cf = config_search_internal(parent, aux,
+ cfargs_canonicalize(cfargs, &store));
return cf;
}
@@ -1256,18 +1240,17 @@ static const char * const msgs[] = {
* not configured, call the given `print' function and return NULL.
*/
device_t
-config_vfound(device_t parent, void *aux, cfprint_t print, cfarg_t tag,
- va_list ap)
+config_found(device_t parent, void *aux, cfprint_t print,
+ const struct cfargs * const cfargs)
{
cfdata_t cf;
- va_list nap;
-
- va_copy(nap, ap);
- cf = config_vsearch(parent, aux, tag, nap);
- va_end(nap);
+ struct cfargs_internal store;
+ const struct cfargs_internal * const args =
+ cfargs_canonicalize(cfargs, &store);
+ cf = config_search_internal(parent, aux, args);
if (cf != NULL) {
- return config_vattach(parent, cf, aux, print, tag, ap);
+ return config_attach_internal(parent, cf, aux, print, args);
}
if (print) {
@@ -1292,19 +1275,6 @@ config_vfound(device_t parent, void *aux
return NULL;
}
-device_t
-config_found(device_t parent, void *aux, cfprint_t print, cfarg_t tag, ...)
-{
- device_t dev;
- va_list ap;
-
- va_start(ap, tag);
- dev = config_vfound(parent, aux, print, tag, ap);
- va_end(ap);
-
- return dev;
-}
-
/*
* As above, but for root devices.
*/
@@ -1316,7 +1286,7 @@ config_rootfound(const char *rootname, v
KERNEL_LOCK(1, NULL);
if ((cf = config_rootsearch(NULL, rootname, aux)) != NULL)
- dev = config_attach(ROOT, cf, aux, NULL, CFARG_EOL);
+ dev = config_attach(ROOT, cf, aux, NULL, CFARGS_NONE);
else
aprint_error("root device %s not configured\n", rootname);
KERNEL_UNLOCK_ONE(NULL);
@@ -1539,8 +1509,8 @@ config_unit_alloc(device_t dev, cfdriver
}
static device_t
-config_vdevalloc(const device_t parent, const cfdata_t cf, cfarg_t tag,
- va_list ap)
+config_devalloc(const device_t parent, const cfdata_t cf,
+ const struct cfargs_internal * const args)
{
cfdriver_t cd;
cfattach_t ca;
@@ -1552,7 +1522,6 @@ config_vdevalloc(const device_t parent,
void *dev_private;
const struct cfiattrdata *ia;
device_lock_t dvl;
- const int *locs;
cd = config_cfdriver_lookup(cf->cf_name);
if (cd == NULL)
@@ -1571,12 +1540,7 @@ config_vdevalloc(const device_t parent,
}
dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
- /*
- * If a handle was supplied to config_attach(), we'll get it
- * assigned automatically here. If not, then we'll get the
- * default invalid handle.
- */
- config_get_cfargs(tag, NULL, NULL, &locs, &dev->dv_handle, ap);
+ dev->dv_handle = args->devhandle;
dev->dv_class = cd->cd_class;
dev->dv_cfdata = cf;
@@ -1598,7 +1562,7 @@ config_vdevalloc(const device_t parent,
xunit = number(&num[sizeof(num)], myunit);
lunit = &num[sizeof(num)] - xunit;
if (lname + lunit > sizeof(dev->dv_xname))
- panic("config_vdevalloc: device name too long");
+ panic("config_devalloc: device name too long");
dvl = device_getlock(dev);
@@ -1613,13 +1577,14 @@ config_vdevalloc(const device_t parent,
else
dev->dv_depth = 0;
dev->dv_flags |= DVF_ACTIVE; /* always initially active */
- if (locs) {
+ if (args->locators) {
KASSERT(parent); /* no locators at root */
ia = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
dev->dv_locators =
kmem_alloc(sizeof(int) * (ia->ci_loclen + 1), KM_SLEEP);
*dev->dv_locators++ = sizeof(int) * (ia->ci_loclen + 1);
- memcpy(dev->dv_locators, locs, sizeof(int) * ia->ci_loclen);
+ memcpy(dev->dv_locators, args->locators,
+ sizeof(int) * ia->ci_loclen);
}
dev->dv_properties = prop_dictionary_create();
KASSERT(dev->dv_properties != NULL);
@@ -1639,19 +1604,6 @@ config_vdevalloc(const device_t parent,
return dev;
}
-static device_t
-config_devalloc(const device_t parent, const cfdata_t cf, cfarg_t tag, ...)
-{
- device_t dev;
- va_list ap;
-
- va_start(ap, tag);
- dev = config_vdevalloc(parent, cf, tag, ap);
- va_end(ap);
-
- return dev;
-}
-
/*
* Create an array of device attach attributes and add it
* to the device's dv_properties dictionary.
@@ -1734,9 +1686,9 @@ config_add_attrib_dict(device_t dev)
/*
* Attach a found device.
*/
-device_t
-config_vattach(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
- cfarg_t tag, va_list ap)
+static device_t
+config_attach_internal(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
+ const struct cfargs_internal * const args)
{
device_t dev;
struct cftable *ct;
@@ -1745,7 +1697,7 @@ config_vattach(device_t parent, cfdata_t
KASSERT(KERNEL_LOCKED_P());
- dev = config_vdevalloc(parent, cf, tag, ap);
+ dev = config_devalloc(parent, cf, args);
if (!dev)
panic("config_attach: allocation of device softc failed");
@@ -1817,18 +1769,14 @@ config_vattach(device_t parent, cfdata_t
device_t
config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
- cfarg_t tag, ...)
+ const struct cfargs *cfargs)
{
- device_t dev;
- va_list ap;
+ struct cfargs_internal store;
KASSERT(KERNEL_LOCKED_P());
- va_start(ap, tag);
- dev = config_vattach(parent, cf, aux, print, tag, ap);
- va_end(ap);
-
- return dev;
+ return config_attach_internal(parent, cf, aux, print,
+ cfargs_canonicalize(cfargs, &store));
}
/*
@@ -1847,7 +1795,8 @@ config_attach_pseudo(cfdata_t cf)
KERNEL_LOCK(1, NULL);
- dev = config_devalloc(ROOT, cf, CFARG_EOL);
+ struct cfargs_internal args = { };
+ dev = config_devalloc(ROOT, cf, &args);
if (!dev)
goto out;
Index: src/sys/sys/device.h
diff -u src/sys/sys/device.h:1.171 src/sys/sys/device.h:1.171.2.1
--- src/sys/sys/device.h:1.171 Sat Jun 12 12:13:51 2021
+++ src/sys/sys/device.h Tue Aug 3 15:00:15 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: device.h,v 1.171 2021/06/12 12:13:51 riastradh Exp $ */
+/* $NetBSD: device.h,v 1.171.2.1 2021/08/03 15:00:15 thorpej Exp $ */
/*
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -412,6 +412,7 @@ TAILQ_HEAD(cftablelist, cftable);
#endif
typedef int (*cfsubmatch_t)(device_t, cfdata_t, const int *, void *);
+typedef int (*cfsearch_t)(device_t, cfdata_t, const int *, void *);
/*
* `configuration' attachment and driver (what the machine-independent
@@ -530,19 +531,39 @@ struct pdevinit {
#define DVUNIT_ANY -1
/*
- * Tags for tag-value argument pairs passed to config_search() and
- * config_found().
+ * Arguments passed to config_search() and config_found().
*/
-typedef enum {
- CFARG_SUBMATCH = 0, /* submatch function (direct config) */
- CFARG_SEARCH = 1, /* search function (indirect config) */
- CFARG_IATTR = 2, /* interface attribute */
- CFARG_LOCATORS = 3, /* locators array */
- CFARG_DEVHANDLE = 4, /* devhandle_t (by value) */
-
- /* ...a value not likely to occur randomly in the wild. */
- CFARG_EOL = 0xeeeeeeee
-} cfarg_t;
+struct cfargs {
+ uintptr_t cfargs_version; /* version field */
+
+ /* version 1 fields */
+ cfsubmatch_t submatch; /* submatch function (direct config) */
+ cfsearch_t search; /* search function (indirect config) */
+ const char * iattr; /* interface attribute */
+ const int * locators; /* locators array */
+ devhandle_t devhandle; /* devhandle_t (by value) */
+
+ /* version 2 fields below here */
+};
+
+#define CFARGS_VERSION 1 /* current cfargs version */
+
+#define CFARGS_NONE NULL /* no cfargs to pass */
+
+/*
+ * Construct a cfargs with this macro, like so:
+ *
+ * CFARGS(.submatch = config_stdsubmatch,
+ * .devhandle = my_devhandle)
+ *
+ * You must supply at least one field. If you don't need any, use the
+ * CFARGS_NONE macro.
+ */
+#define CFARGS(...) \
+ &((const struct cfargs){ \
+ .cfargs_version = CFARGS_VERSION, \
+ __VA_ARGS__ \
+ })
#ifdef _KERNEL
@@ -587,25 +608,15 @@ const struct cfiattrdata *cfiattr_lookup
const char *cfdata_ifattr(const struct cfdata *);
int config_stdsubmatch(device_t, cfdata_t, const int *, void *);
-cfdata_t config_search(device_t, void *, cfarg_t, ...);
+cfdata_t config_search(device_t, void *, const struct cfargs *);
cfdata_t config_rootsearch(cfsubmatch_t, const char *, void *);
-device_t config_found(device_t, void *, cfprint_t, cfarg_t, ...);
+device_t config_found(device_t, void *, cfprint_t, const struct cfargs *);
device_t config_rootfound(const char *, void *);
-device_t config_attach(device_t, cfdata_t, void *, cfprint_t, cfarg_t, ...);
+device_t config_attach(device_t, cfdata_t, void *, cfprint_t,
+ const struct cfargs *);
int config_match(device_t, cfdata_t, void *);
int config_probe(device_t, cfdata_t, void *);
-#if defined(__SUBR_AUTOCONF_PRIVATE)
-/*
- * XXX Some ports abuse the internals of autoconfiguration, so we need
- * XXX provide these symbols to them for the time being.
- */
-cfdata_t config_vsearch(device_t, void *, cfarg_t, va_list);
-device_t config_vfound(device_t, void *, cfprint_t, cfarg_t, va_list);
-device_t config_vattach(device_t, cfdata_t, void *, cfprint_t, cfarg_t,
- va_list);
-#endif /* __SUBR_AUTOCONF_PRIVATE */
-
bool ifattr_match(const char *, const char *);
device_t config_attach_pseudo(cfdata_t);