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