svn commit: r310295 - in head/sys: conf dev/bhnd/nvram modules/bhnd

Landon J. Fuller landonf at FreeBSD.org
Mon Dec 19 20:28:29 UTC 2016


Author: landonf
Date: Mon Dec 19 20:28:27 2016
New Revision: 310295
URL: https://svnweb.freebsd.org/changeset/base/310295

Log:
  bhnd(4): NVRAM device path support.
  
  Implements bhnd_nvram_store support for parsing and operating over NVRAM
  device paths, and device path aliases, as well as tracking per-path NVRAM
  variable writes.
  
  Approved by:	adrian (mentor)
  Differential Revision:	https://reviews.freebsd.org/D8760

Added:
  head/sys/dev/bhnd/nvram/bhnd_nvram_store_subr.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/nvram/bhnd_nvram_data.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_private.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_store.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_store.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_storevar.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c
  head/sys/modules/bhnd/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/conf/files	Mon Dec 19 20:28:27 2016	(r310295)
@@ -1244,6 +1244,7 @@ dev/bhnd/nvram/bhnd_nvram_ioptr.c	option
 dev/bhnd/nvram/bhnd_nvram_iores.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_plist.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_store.c	optional bhnd
+dev/bhnd/nvram/bhnd_nvram_store_subr.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_subr.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_value.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_value_fmts.c	optional bhnd

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data.c	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data.c	Mon Dec 19 20:28:27 2016	(r310295)
@@ -350,7 +350,26 @@ bhnd_nvram_data_caps(struct bhnd_nvram_d
 const char *
 bhnd_nvram_data_next(struct bhnd_nvram_data *nv, void **cookiep)
 {
-	return (nv->cls->op_next(nv, cookiep));
+	const char	*name;
+#ifdef BHND_NV_INVARIANTS
+	void		*prev = *cookiep;
+#endif
+
+	/* Fetch next */
+	if ((name = nv->cls->op_next(nv, cookiep)) == NULL)
+		return (NULL);
+
+	/* Enforce precedence ordering invariant between bhnd_nvram_data_next()
+	 * and bhnd_nvram_data_getvar_order() */
+#ifdef BHND_NV_INVARIANTS
+	if (prev != NULL &&
+	    bhnd_nvram_data_getvar_order(nv, prev, *cookiep) > 0)
+	{
+		BHND_NV_PANIC("%s: returned out-of-order entry", __FUNCTION__);
+	}
+#endif
+
+	return (name);
 }
 
 /**
@@ -388,7 +407,7 @@ bhnd_nvram_data_generic_find(struct bhnd
 
 	cookiep = NULL;
 	while ((next = bhnd_nvram_data_next(nv, &cookiep))) {
-		if (strcasecmp(name, next) == 0)
+		if (strcmp(name, next) == 0)
 			return (cookiep);
 	}
 
@@ -397,6 +416,37 @@ bhnd_nvram_data_generic_find(struct bhnd
 }
 
 /**
+ * Compare the declaration order of two NVRAM variables.
+ * 
+ * Variable declaration order is used to determine the current order of
+ * the variables in the source data, as well as to determine the precedence
+ * of variable declarations in data sources that define duplicate names.
+ * 
+ * The comparison order will match the order of variables returned via
+ * bhnd_nvstore_path_data_next().
+ *
+ * @param		nv		The NVRAM data.
+ * @param		cookiep1	An NVRAM variable cookie previously
+ *					returned via bhnd_nvram_data_next() or
+ *					bhnd_nvram_data_find().
+ * @param		cookiep2	An NVRAM variable cookie previously
+ *					returned via bhnd_nvram_data_next() or
+ *					bhnd_nvram_data_find().
+ *
+ * @retval <= -1	If @p cookiep1 has an earlier declaration order than
+ *			@p cookiep2.
+ * @retval 0		If @p cookiep1 and @p cookiep2 are identical.
+ * @retval >= 1		If @p cookiep has a later declaration order than
+ *			@p cookiep2.
+ */
+int
+bhnd_nvram_data_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
+    void *cookiep2)
+{
+	return (nv->cls->op_getvar_order(nv, cookiep1, cookiep2));
+}
+
+/**
  * Read a variable and decode as @p type.
  *
  * @param		nv	The NVRAM data.
@@ -423,6 +473,58 @@ bhnd_nvram_data_getvar(struct bhnd_nvram
 	return (nv->cls->op_getvar(nv, cookiep, buf, len, type));
 }
 
+/*
+ * Common bhnd_nvram_data_getvar_ptr() wrapper used by
+ * bhnd_nvram_data_generic_rp_getvar() and
+ * bhnd_nvram_data_generic_rp_copy_val().
+ *
+ * If a variable definition for the requested variable is found via
+ * bhnd_nvram_find_vardefn(), the definition will be used to populate fmt.
+ */
+static const void *
+bhnd_nvram_data_getvar_ptr_info(struct bhnd_nvram_data *nv, void *cookiep,
+    size_t *len, bhnd_nvram_type *type, const bhnd_nvram_val_fmt **fmt)
+{
+	const struct bhnd_nvram_vardefn	*vdefn;
+	const char			*name;
+	const void			*vptr;
+
+	BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
+	    ("instance does not advertise READ_PTR support"));
+
+	/* Fetch pointer to variable data */
+	vptr = bhnd_nvram_data_getvar_ptr(nv, cookiep, len, type);
+	if (vptr == NULL)
+		return (NULL);
+
+	/* Select a default value format implementation */
+
+
+	/* Fetch the reference variable name */
+	name = bhnd_nvram_data_getvar_name(nv, cookiep);
+
+	/* Trim path prefix, if any; the Broadcom NVRAM format assumes a global
+	 * namespace for all variable definitions */
+	if (bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_DEVPATHS)
+		name = bhnd_nvram_trim_path_name(name);
+
+	/* Check the variable definition table for a matching entry; if
+	 * it exists, use it to populate the value format. */
+	vdefn = bhnd_nvram_find_vardefn(name);
+	if (vdefn != NULL) {
+		BHND_NV_ASSERT(vdefn->fmt != NULL,
+		    ("NULL format for %s", name));
+		*fmt = vdefn->fmt;
+	} else if (*type == BHND_NVRAM_TYPE_STRING) {
+		/* Default to Broadcom-specific string interpretation */
+		*fmt = &bhnd_nvram_val_bcm_string_fmt;
+	} else {
+		/* Fall back on native formatting */
+		*fmt = bhnd_nvram_val_default_fmt(*type);
+	}
+
+	return (vptr);
+}
 
 /**
  * A generic implementation of bhnd_nvram_data_getvar().
@@ -432,17 +534,15 @@ bhnd_nvram_data_getvar(struct bhnd_nvram
  * of the caller.
  *
  * If a variable definition for the requested variable is available via
- * bhnd_nvram_find_vardefn(), the definition will be used to provide
- * formatting hints to bhnd_nvram_coerce_value().
+ * bhnd_nvram_find_vardefn(), the definition will be used to provide a
+ * formatting instance to bhnd_nvram_val_init().
  */
 int
 bhnd_nvram_data_generic_rp_getvar(struct bhnd_nvram_data *nv, void *cookiep,
     void *outp, size_t *olen, bhnd_nvram_type otype)
 {
 	bhnd_nvram_val			 val;
-	const struct bhnd_nvram_vardefn	*vdefn;
 	const bhnd_nvram_val_fmt	*fmt;
-	const char			*name;
 	const void			*vptr;
 	bhnd_nvram_type			 vtype;
 	size_t				 vlen;
@@ -451,28 +551,12 @@ bhnd_nvram_data_generic_rp_getvar(struct
 	BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
 	    ("instance does not advertise READ_PTR support"));
 
-	/* Fetch pointer to our variable data */
-	vptr = bhnd_nvram_data_getvar_ptr(nv, cookiep, &vlen, &vtype);
+	/* Fetch variable data and value format*/
+	vptr = bhnd_nvram_data_getvar_ptr_info(nv, cookiep, &vlen, &vtype,
+	    &fmt);
 	if (vptr == NULL)
 		return (EINVAL);
 
-	/* Use the NVRAM string support */
-	switch (vtype) {
-	case BHND_NVRAM_TYPE_STRING:
-	case BHND_NVRAM_TYPE_STRING_ARRAY:
-		fmt = &bhnd_nvram_val_bcm_string_fmt;
-		break;
-	default:
-		fmt = NULL;
-	}
-
-	/* Check the variable definition table for a matching entry; if
-	 * it exists, use it to populate the value format. */
-	name = bhnd_nvram_data_getvar_name(nv, cookiep);
-	vdefn = bhnd_nvram_find_vardefn(name);
-	if (vdefn != NULL)
-		fmt = vdefn->fmt;
-
 	/* Attempt value coercion */
 	error = bhnd_nvram_val_init(&val, fmt, vptr, vlen, vtype,
 	    BHND_NVRAM_VAL_BORROW_DATA);
@@ -487,6 +571,63 @@ bhnd_nvram_data_generic_rp_getvar(struct
 }
 
 /**
+ * Return a caller-owned copy of an NVRAM entry's variable data.
+ * 
+ * The caller is responsible for deallocating the returned value via
+ * bhnd_nvram_val_release().
+ *
+ * @param	nv	The NVRAM data.
+ * @param	cookiep	An NVRAM variable cookie previously returned
+ *			via bhnd_nvram_data_next() or bhnd_nvram_data_find().
+ * @param[out]	value	On success, the caller-owned value instance.
+ *
+ * @retval 0		success
+ * @retval ENOMEM	If allocation fails.
+ * @retval non-zero	If initialization of the value otherwise fails, a
+ *			regular unix error code will be returned.
+ */
+int
+bhnd_nvram_data_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
+    bhnd_nvram_val **value)
+{
+	return (nv->cls->op_copy_val(nv, cookiep, value));
+}
+
+/**
+ * A generic implementation of bhnd_nvram_data_copy_val().
+ * 
+ * This implementation will call bhnd_nvram_data_getvar_ptr() to fetch
+ * a pointer to the variable data and perform data coercion on behalf
+ * of the caller.
+ *
+ * If a variable definition for the requested variable is available via
+ * bhnd_nvram_find_vardefn(), the definition will be used to provide a
+ * formatting instance to bhnd_nvram_val_init().
+ */
+int
+bhnd_nvram_data_generic_rp_copy_val(struct bhnd_nvram_data *nv,
+    void *cookiep, bhnd_nvram_val **value)
+{
+	const bhnd_nvram_val_fmt	*fmt;
+	const void			*vptr;
+	bhnd_nvram_type			 vtype;
+	size_t				 vlen;
+
+	BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
+	    ("instance does not advertise READ_PTR support"));
+
+	/* Fetch variable data and value format*/
+	vptr = bhnd_nvram_data_getvar_ptr_info(nv, cookiep, &vlen, &vtype,
+	    &fmt);
+	if (vptr == NULL)
+		return (EINVAL);
+
+	/* Allocate and return the new value instance */
+	return (bhnd_nvram_val_new(value, fmt, vptr, vlen, vtype,
+	    BHND_NVRAM_VAL_DYNAMIC));
+}
+
+/**
  * If available and supported by the NVRAM data instance, return a reference
  * to the internal buffer containing an entry's variable data,
  * 
@@ -526,3 +667,44 @@ bhnd_nvram_data_getvar_name(struct bhnd_
 {
 	return (nv->cls->op_getvar_name(nv, cookiep));
 }
+
+/**
+ * Filter a request to set variable @p name with @p value.
+ * 
+ * On success, the caller owns a reference to @p result, and must release
+ * any held resources via bhnd_nvram_val_release().
+ * 
+ * @param	nv	The NVRAM data instance.
+ * @param	name	The name of the variable to be set.
+ * @param	value	The proposed value to be set.
+ * @param[out]	result	On success, a caller-owned reference to the filtered
+ *			value to be set.
+ * 
+ * @retval	0	success
+ * @retval	ENOENT	if @p name is unrecognized by @p nv.
+ * @retval	EINVAL	if @p name is read-only.
+ * @retval	EINVAL	if @p value cannot be converted to the required value
+ *			type.
+ */
+int
+bhnd_nvram_data_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
+    bhnd_nvram_val *value, bhnd_nvram_val **result)
+{
+	return (nv->cls->op_filter_setvar(nv, name, value, result));
+}
+
+/**
+ * Filter a request to delete variable @p name.
+ * 
+ * @param	nv	The NVRAM data instance.
+ * @param	name	The name of the variable to be deleted.
+ * 
+ * @retval	0	success
+ * @retval	ENOENT	if @p name is unrecognized by @p nv.
+ * @retval	EINVAL	if @p name is read-only.
+ */
+int
+bhnd_nvram_data_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
+{
+	return (nv->cls->op_filter_unsetvar(nv, name));
+}

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data.h
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data.h	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data.h	Mon Dec 19 20:28:27 2016	(r310295)
@@ -44,6 +44,7 @@
 
 #include "bhnd_nvram.h"
 #include "bhnd_nvram_io.h"
+#include "bhnd_nvram_value.h"
 
 /* NVRAM data class */
 typedef struct bhnd_nvram_data_class bhnd_nvram_data_class;
@@ -108,7 +109,6 @@ void			 bhnd_nvram_data_release(struct b
 bhnd_nvram_data_class	*bhnd_nvram_data_get_class(struct bhnd_nvram_data *nv);
 
 size_t			 bhnd_nvram_data_count(struct bhnd_nvram_data *nv);
-
 int			 bhnd_nvram_data_size(struct bhnd_nvram_data *nv,
 			     size_t *size);
 
@@ -119,10 +119,13 @@ uint32_t		 bhnd_nvram_data_caps(struct b
 
 const char		*bhnd_nvram_data_next(struct bhnd_nvram_data *nv,
 			     void **cookiep);
-
 void			*bhnd_nvram_data_find(struct bhnd_nvram_data *nv,
 			     const char *name);
 
+int			 bhnd_nvram_data_getvar_order(
+			     struct bhnd_nvram_data *nv, void *cookiep1,
+			     void *cookiep2);
+
 int			 bhnd_nvram_data_getvar(struct bhnd_nvram_data *nv,
 			     void *cookiep, void *buf, size_t *len,
 			     bhnd_nvram_type type);
@@ -133,4 +136,13 @@ const void		*bhnd_nvram_data_getvar_ptr(
 const char		*bhnd_nvram_data_getvar_name(struct bhnd_nvram_data *nv,
 			     void *cookiep);
 
+int			 bhnd_nvram_data_copy_val(struct bhnd_nvram_data *nv,
+			     void *cookiep, bhnd_nvram_val **val);
+
+int			 bhnd_nvram_data_filter_setvar(
+			     struct bhnd_nvram_data *nv, const char *name,
+			     bhnd_nvram_val *value, bhnd_nvram_val **result);
+int			 bhnd_nvram_data_filter_unsetvar(
+			     struct bhnd_nvram_data *nv, const char *name);
+
 #endif /* _BHND_NVRAM_BHND_NVRAM_DATA_H_ */

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c	Mon Dec 19 20:28:27 2016	(r310295)
@@ -618,7 +618,7 @@ bhnd_nvram_bcm_next(struct bhnd_nvram_da
 		return (NULL);
 	}
 
-	*cookiep = (void *)(uintptr_t)envp;
+	*cookiep = __DECONST(void *, envp);
 	return (envp);
 }
 
@@ -629,12 +629,52 @@ bhnd_nvram_bcm_find(struct bhnd_nvram_da
 }
 
 static int
+bhnd_nvram_bcm_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
+    void *cookiep2)
+{
+	struct bhnd_nvram_bcm		*bcm;
+	struct bhnd_nvram_bcm_hvar	*hvar1, *hvar2;
+
+	bcm = (struct bhnd_nvram_bcm *)nv;
+
+	hvar1 = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep1);
+	hvar2 = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep2);
+
+	/* Header variables are always ordered below any variables defined
+	 * in the BCM data */
+	if (hvar1 != NULL && hvar2 == NULL) {
+		return (1);	/* hvar follows non-hvar */
+	} else if (hvar1 == NULL && hvar2 != NULL) {
+		return (-1);	/* non-hvar precedes hvar */
+	}
+
+	/* Otherwise, both cookies are either hvars or non-hvars. We can
+	 * safely fall back on pointer order, which will provide a correct
+	 * ordering matching the behavior of bhnd_nvram_data_next() for
+	 * both cases */
+	if (cookiep1 < cookiep2)
+		return (-1);
+
+	if (cookiep1 > cookiep2)
+		return (1);
+
+	return (0);
+}
+
+static int
 bhnd_nvram_bcm_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
     size_t *len, bhnd_nvram_type type)
 {
 	return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
 }
 
+static int
+bhnd_nvram_bcm_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
+    bhnd_nvram_val **value)
+{
+	return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
+}
+
 static const void *
 bhnd_nvram_bcm_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
     size_t *len, bhnd_nvram_type *type)
@@ -683,6 +723,35 @@ bhnd_nvram_bcm_getvar_name(struct bhnd_n
 	return (cookiep);
 }
 
+static int
+bhnd_nvram_bcm_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
+    bhnd_nvram_val *value, bhnd_nvram_val **result)
+{
+	bhnd_nvram_val	*str;
+	int		 error;
+
+	/* Name (trimmed of any path prefix) must be valid */
+	if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
+		return (EINVAL);
+
+	/* Value must be bcm-formatted string */
+	error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
+	    value, BHND_NVRAM_VAL_DYNAMIC);
+	if (error)
+		return (error);
+
+	/* Success. Transfer result ownership to the caller. */
+	*result = str;
+	return (0);
+}
+
+static int
+bhnd_nvram_bcm_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
+{
+	/* We permit deletion of any variable */
+	return (0);
+}
+
 /**
  * Return the internal BCM data reference for a header-defined variable
  * with @p name, or NULL if none exists.

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c	Mon Dec 19 20:28:27 2016	(r310295)
@@ -351,12 +351,32 @@ bhnd_nvram_bcmraw_find(struct bhnd_nvram
 }
 
 static int
+bhnd_nvram_bcmraw_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
+    void *cookiep2)
+{
+	if (cookiep1 < cookiep2)
+		return (-1);
+
+	if (cookiep1 > cookiep2)
+		return (1);
+
+	return (0);
+}
+
+static int
 bhnd_nvram_bcmraw_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
     size_t *len, bhnd_nvram_type type)
 {
 	return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
 }
 
+static int
+bhnd_nvram_bcmraw_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
+    bhnd_nvram_val **value)
+{
+	return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
+}
+
 static const void *
 bhnd_nvram_bcmraw_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
     size_t *len, bhnd_nvram_type *type)
@@ -378,3 +398,32 @@ bhnd_nvram_bcmraw_getvar_name(struct bhn
 	/* Cookie points to key\0value\0 */
 	return (cookiep);
 }
+
+static int
+bhnd_nvram_bcmraw_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
+    bhnd_nvram_val *value, bhnd_nvram_val **result)
+{
+	bhnd_nvram_val	*str;
+	int		 error;
+
+	/* Name (trimmed of any path prefix) must be valid */
+	if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
+		return (EINVAL);
+
+	/* Value must be bcm-formatted string */
+	error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
+	    value, BHND_NVRAM_VAL_DYNAMIC);
+	if (error)
+		return (error);
+
+	/* Success. Transfer result ownership to the caller. */
+	*result = str;
+	return (0);
+}
+
+static int
+bhnd_nvram_bcmraw_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
+{
+	/* We permit deletion of any variable */
+	return (0);
+}

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c	Mon Dec 19 20:28:27 2016	(r310295)
@@ -77,8 +77,10 @@ union bhnd_nvram_btxt_ident {
 	char		btxt[8];
 };
 
-static size_t	bhnd_nvram_btxt_io_offset(struct bhnd_nvram_btxt *btxt,
-					  void *cookiep);
+static void	*bhnd_nvram_btxt_offset_to_cookiep(struct bhnd_nvram_btxt *btxt,
+		 size_t io_offset);
+static size_t	 bhnd_nvram_btxt_cookiep_to_offset(struct bhnd_nvram_btxt *btxt,
+		     void *cookiep);
 
 static int	bhnd_nvram_btxt_entry_len(struct bhnd_nvram_io *io,
 		    size_t offset, size_t *line_len, size_t *env_len);
@@ -322,35 +324,40 @@ bhnd_nvram_btxt_next(struct bhnd_nvram_d
 	btxt = (struct bhnd_nvram_btxt *)nv;
 
 	io_size = bhnd_nvram_io_getsize(btxt->data);
-	io_offset = bhnd_nvram_btxt_io_offset(btxt, *cookiep);
+
+	if (*cookiep == NULL) {
+		/* Start search at initial file offset */
+		io_offset = 0x0;
+	} else {
+		/* Start search after the current entry */
+		io_offset = bhnd_nvram_btxt_cookiep_to_offset(btxt, *cookiep);
+
+		/* Scan past the current entry by finding the next newline */
+		error = bhnd_nvram_btxt_seek_eol(btxt->data, &io_offset);
+		if (error) {
+			BHND_NV_LOG("unexpected error in seek_eol(): %d\n",
+			    error);
+			return (NULL);
+		}
+	}
 
 	/* Already at EOF? */
 	if (io_offset == io_size)
 		return (NULL);
 
-	/* Seek to the next entry (if any) */
-	if ((error = bhnd_nvram_btxt_seek_eol(btxt->data, &io_offset))) {
-		BHND_NV_LOG("unexpected error in seek_eol(): %d\n", error);
-		return (NULL);
-	}
-
+	/* Seek to the first valid entry, or EOF */
 	if ((error = bhnd_nvram_btxt_seek_next(btxt->data, &io_offset))) {
 		BHND_NV_LOG("unexpected error in seek_next(): %d\n", error);
 		return (NULL);
 	}
 
-	/* Provide the new cookie for this offset */
-	if (io_offset > UINTPTR_MAX) {
-		BHND_NV_LOG("io_offset > UINPTR_MAX!\n");
-		return (NULL);
-	}
-
-	*cookiep = (void *)(uintptr_t)io_offset;
-
 	/* Hit EOF? */
 	if (io_offset == io_size)
 		return (NULL);
 
+	/* Provide the new cookie for this offset */
+	*cookiep = bhnd_nvram_btxt_offset_to_cookiep(btxt, io_offset);
+
 	/* Fetch the name pointer; it must be at least 1 byte long */
 	error = bhnd_nvram_io_read_ptr(btxt->data, io_offset, &nptr, 1, NULL);
 	if (error) {
@@ -363,12 +370,32 @@ bhnd_nvram_btxt_next(struct bhnd_nvram_d
 }
 
 static int
+bhnd_nvram_btxt_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
+    void *cookiep2)
+{
+	if (cookiep1 < cookiep2)
+		return (-1);
+
+	if (cookiep1 > cookiep2)
+		return (1);
+
+	return (0);
+}
+
+static int
 bhnd_nvram_btxt_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
     size_t *len, bhnd_nvram_type type)
 {
 	return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
 }
 
+static int
+bhnd_nvram_btxt_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
+    bhnd_nvram_val **value)
+{
+	return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
+}
+
 const void *
 bhnd_nvram_btxt_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
     size_t *len, bhnd_nvram_type *type)
@@ -383,7 +410,7 @@ bhnd_nvram_btxt_getvar_ptr(struct bhnd_n
 	btxt = (struct bhnd_nvram_btxt *)nv;
 	
 	io_size = bhnd_nvram_io_getsize(btxt->data);
-	io_offset = bhnd_nvram_btxt_io_offset(btxt, cookiep);
+	io_offset = bhnd_nvram_btxt_cookiep_to_offset(btxt, cookiep);
 
 	/* At EOF? */
 	if (io_offset == io_size)
@@ -429,7 +456,7 @@ bhnd_nvram_btxt_getvar_name(struct bhnd_
 	btxt = (struct bhnd_nvram_btxt *)nv;
 	
 	io_size = bhnd_nvram_io_getsize(btxt->data);
-	io_offset = bhnd_nvram_btxt_io_offset(btxt, cookiep);
+	io_offset = bhnd_nvram_btxt_cookiep_to_offset(btxt, cookiep);
 
 	/* At EOF? */
 	if (io_offset == io_size)
@@ -444,20 +471,51 @@ bhnd_nvram_btxt_getvar_name(struct bhnd_
 	return (ptr);
 }
 
-/* Convert cookie back to an I/O offset */
+/**
+ * Return a cookiep for the given I/O offset.
+ */
+static void *
+bhnd_nvram_btxt_offset_to_cookiep(struct bhnd_nvram_btxt *btxt,
+    size_t io_offset)
+{
+	const void	*ptr;
+	int		 error;
+
+	BHND_NV_ASSERT(io_offset < bhnd_nvram_io_getsize(btxt->data),
+	    ("io_offset %zu out-of-range", io_offset));
+	BHND_NV_ASSERT(io_offset < UINTPTR_MAX,
+	    ("io_offset %#zx exceeds UINTPTR_MAX", io_offset));
+
+	error = bhnd_nvram_io_read_ptr(btxt->data, 0x0, &ptr, io_offset, NULL);
+	if (error)
+		BHND_NV_PANIC("error mapping offset %zu: %d", io_offset, error);
+
+	ptr = (const uint8_t *)ptr + io_offset;
+	return (__DECONST(void *, ptr));
+}
+
+/* Convert a cookiep back to an I/O offset */
 static size_t
-bhnd_nvram_btxt_io_offset(struct bhnd_nvram_btxt *btxt, void *cookiep)
+bhnd_nvram_btxt_cookiep_to_offset(struct bhnd_nvram_btxt *btxt, void *cookiep)
 {
-	size_t		io_size;
-	uintptr_t	cval;
+	const void	*ptr;
+	intptr_t	 offset;
+	size_t		 io_size;
+	int		 error;
+
+	BHND_NV_ASSERT(cookiep != NULL, ("null cookiep"));
 
 	io_size = bhnd_nvram_io_getsize(btxt->data);
-	cval = (uintptr_t)cookiep;
+	error = bhnd_nvram_io_read_ptr(btxt->data, 0x0, &ptr, io_size, NULL);
+	if (error)
+		BHND_NV_PANIC("error mapping offset %zu: %d", io_size, error);
 
-	BHND_NV_ASSERT(cval < SIZE_MAX, ("cookie > SIZE_MAX)"));
-	BHND_NV_ASSERT(cval <= io_size, ("cookie > io_size)"));
+	offset = (const uint8_t *)cookiep - (const uint8_t *)ptr;
+	BHND_NV_ASSERT(offset >= 0, ("invalid cookiep"));
+	BHND_NV_ASSERT((uintptr_t)offset < SIZE_MAX, ("cookiep > SIZE_MAX)"));
+	BHND_NV_ASSERT((uintptr_t)offset <= io_size, ("cookiep > io_size)"));
 
-	return ((size_t)cval);
+	return ((size_t)offset);
 }
 
 /* Determine the entry length and env 'key=value' string length of the entry
@@ -584,3 +642,50 @@ bhnd_nvram_btxt_seek_next(struct bhnd_nv
 	*offset += (p - baseptr);
 	return (0);
 }
+
+static int
+bhnd_nvram_btxt_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
+    bhnd_nvram_val *value, bhnd_nvram_val **result)
+{
+	bhnd_nvram_val	*str;
+	const char	*inp;
+	bhnd_nvram_type	 itype;
+	size_t		 ilen;
+	int		 error;
+
+	/* Name (trimmed of any path prefix) must be valid */
+	if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
+		return (EINVAL);
+
+	/* Value must be bcm-formatted string */
+	error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
+	    value, BHND_NVRAM_VAL_DYNAMIC);
+	if (error)
+		return (error);
+
+	/* Value string must not contain our record delimiter character ('\n'),
+	 * or our comment character ('#') */
+	inp = bhnd_nvram_val_bytes(str, &ilen, &itype);
+	BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_STRING, ("non-string value"));
+	for (size_t i = 0; i < ilen; i++) {
+		switch (inp[i]) {
+		case '\n':
+		case '#':
+			BHND_NV_LOG("invalid character (%#hhx) in value\n",
+			    inp[i]);
+			bhnd_nvram_val_release(str);
+			return (EINVAL);
+		}
+	}
+
+	/* Success. Transfer result ownership to the caller. */
+	*result = str;
+	return (0);
+}
+
+static int
+bhnd_nvram_btxt_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
+{
+	/* We permit deletion of any variable */
+	return (0);
+}

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c	Mon Dec 19 20:28:27 2016	(r310295)
@@ -666,25 +666,34 @@ bhnd_nvram_sprom_read_offset(struct bhnd
 	return (0);
 }
 
+/**
+ * Common variable decoding; fetches and decodes variable to @p val,
+ * using @p storage for actual data storage.
+ * 
+ * The returned @p val instance will hold a borrowed reference to @p storage,
+ * and must be copied via bhnd_nvram_val_copy() if it will be referenced beyond
+ * the lifetime of @p storage.
+ *
+ * The caller is responsible for releasing any allocated value state
+ * via bhnd_nvram_val_release().
+ */
 static int
-bhnd_nvram_sprom_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
-    size_t *len, bhnd_nvram_type otype)
+bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
+    union bhnd_nvram_sprom_storage *storage, bhnd_nvram_val *val)
 {
-	bhnd_nvram_val			 val;
 	struct bhnd_nvram_sprom		*sp;
-	struct sprom_opcode_idx		*idx;
+	struct sprom_opcode_idx		*entry;
 	const struct bhnd_nvram_vardefn	*var;
-	union bhnd_nvram_sprom_storage	 storage;
 	union bhnd_nvram_sprom_storage	*inp;
-	union bhnd_nvram_sprom_intv	 intv;
 	bhnd_nvram_type			 var_btype;
+	union bhnd_nvram_sprom_intv	 intv;
 	size_t				 ilen, ipos, iwidth;
 	size_t				 nelem;
 	bool				 all_bits_set;
 	int				 error;
 
 	sp = (struct bhnd_nvram_sprom *)nv;
-	idx = cookiep;
+	entry = cookiep;
 
 	BHND_NV_ASSERT(cookiep != NULL, ("NULL variable cookiep"));
 
@@ -699,7 +708,7 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 	 * canonical NVRAM variable definition, but some SPROM layouts may
 	 * define a smaller element count.
 	 */
-	if ((error = sprom_opcode_parse_var(&sp->state, idx))) {
+	if ((error = sprom_opcode_parse_var(&sp->state, entry))) {
 		BHND_NV_LOG("variable evaluation failed: %d\n", error);
 		return (error);
 	}
@@ -724,9 +733,9 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 	}
 	ilen = nelem * iwidth;
 
-	/* Decode into our own local storage. */
-	inp = &storage;
-	if (ilen > sizeof(storage)) {
+	/* Decode into our caller's local storage */
+	inp = storage;
+	if (ilen > sizeof(*storage)) {
 		BHND_NV_LOG("error decoding '%s', SPROM_ARRAY_MAXLEN "
 		    "incorrect\n", var->name);
 		return (EFTYPE);
@@ -739,7 +748,7 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 	/*
 	 * Decode the SPROM data, iteratively decoding up to nelem values.
 	 */
-	if ((error = sprom_opcode_state_seek(&sp->state, idx))) {
+	if ((error = sprom_opcode_state_seek(&sp->state, entry))) {
 		BHND_NV_LOG("variable seek failed: %d\n", error);
 		return (error);
 	}
@@ -840,8 +849,9 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 
 			/* Perform coercion of the array element */
 			nbyte = iwidth;
-			error = bhnd_nvram_value_coerce(&intv, sizeof(intv),
-			    intv_type, ptr, &nbyte, var_btype);
+			error = bhnd_nvram_value_coerce(&intv.u32,
+			    sizeof(intv.u32), intv_type, ptr, &nbyte,
+			    var_btype);
 			if (error)
 				return (error);
 
@@ -871,13 +881,45 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 	if ((var->flags & BHND_NVRAM_VF_IGNALL1) && all_bits_set)
 		return (ENOENT);
 
+	/* Provide value wrapper */
+	return (bhnd_nvram_val_init(val, var->fmt, inp, ilen, var->type,
+	    BHND_NVRAM_VAL_BORROW_DATA));
+		return (error);
+}
+
+static int
+bhnd_nvram_sprom_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
+    void *cookiep2)
+{
+	struct sprom_opcode_idx_entry *e1, *e2;
+
+	e1 = cookiep1;
+	e2 = cookiep2;
 
-	/* Perform value coercion from our local representation */
-	error = bhnd_nvram_val_init(&val, var->fmt, inp, ilen, var->type,
-	    BHND_NVRAM_VAL_BORROW_DATA);
+	/* Use the index entry order; this matches the order of variables
+	 * returned via bhnd_nvram_sprom_next() */
+	if (e1 < e2)
+		return (-1);
+	else if (e1 > e2)
+		return (1);
+
+	return (0);
+}
+
+static int
+bhnd_nvram_sprom_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
+    size_t *len, bhnd_nvram_type otype)
+{
+	bhnd_nvram_val			val;
+	union bhnd_nvram_sprom_storage	storage;
+	int				error;
+
+	/* Decode variable to a new value instance */
+	error = bhnd_nvram_sprom_getvar_common(nv, cookiep, &storage, &val);
 	if (error)
 		return (error);
 
+	/* Perform value coercion */
 	error = bhnd_nvram_val_encode(&val, buf, len, otype);
 
 	/* Clean up */
@@ -885,6 +927,29 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 	return (error);
 }
 
+static int
+bhnd_nvram_sprom_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
+    bhnd_nvram_val **value)
+{
+	bhnd_nvram_val			val;
+	union bhnd_nvram_sprom_storage	storage;
+	int				error;
+
+	/* Decode variable to a new value instance */
+	error = bhnd_nvram_sprom_getvar_common(nv, cookiep, &storage, &val);
+	if (error)
+		return (error);
+
+	/* Attempt to copy to heap */
+	*value = bhnd_nvram_val_copy(&val);
+	bhnd_nvram_val_release(&val);
+
+	if (*value == NULL)
+		return (ENOMEM);
+
+	return (0);
+}
+
 static const void *
 bhnd_nvram_sprom_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
     size_t *len, bhnd_nvram_type *type)
@@ -906,6 +971,21 @@ bhnd_nvram_sprom_getvar_name(struct bhnd
 	return (var->name);
 }
 
+static int
+bhnd_nvram_sprom_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
+    bhnd_nvram_val *value, bhnd_nvram_val **result)
+{
+	// XXX TODO
+	return (ENXIO);
+}
+
+static int
+bhnd_nvram_sprom_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
+{
+	// XXX TODO
+	return (ENXIO);
+}
+
 /**
  * Initialize SPROM opcode evaluation state.
  * 

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c	Mon Dec 19 20:26:10 2016	(r310294)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c	Mon Dec 19 20:28:27 2016	(r310295)
@@ -82,6 +82,10 @@ struct bhnd_nvram_tlv_env {
 	(((_env)->hdr.size < sizeof((_env)->flags)) ? 0 :	\
 	    ((_env)->hdr.size - sizeof((_env)->flags)))
 
+/* Maximum supported length of the envp data field, in bytes */
+#define	NVRAM_TLV_ENVP_DATA_MAX_LEN	\
+	(UINT8_MAX - sizeof(uint8_t) /* flags */)
+
 	
 static int				 bhnd_nvram_tlv_parse_size(
 					     struct bhnd_nvram_io *io,
@@ -368,12 +372,32 @@ bhnd_nvram_tlv_find(struct bhnd_nvram_da
 }
 
 static int
+bhnd_nvram_tlv_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
+    void *cookiep2)
+{
+	if (cookiep1 < cookiep2)
+		return (-1);
+
+	if (cookiep1 > cookiep2)
+		return (1);
+
+	return (0);
+}
+
+static int
 bhnd_nvram_tlv_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
     size_t *len, bhnd_nvram_type type)
 {
 	return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
 }
 
+static int
+bhnd_nvram_tlv_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
+    bhnd_nvram_val **value)
+{
+	return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
+}
+
 static const void *
 bhnd_nvram_tlv_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
     size_t *len, bhnd_nvram_type *type)
@@ -417,6 +441,61 @@ bhnd_nvram_tlv_getvar_name(struct bhnd_n
 	return (&env->envp[0]);
 }
 
+static int
+bhnd_nvram_tlv_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
+    bhnd_nvram_val *value, bhnd_nvram_val **result)
+{
+	bhnd_nvram_val	*str;
+	const char	*inp;
+	bhnd_nvram_type	 itype;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list