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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to