Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Dec 2016 20:20:34 +0000 (UTC)
From:      "Landon J. Fuller" <landonf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310292 - in head/sys: conf dev/bhnd/nvram modules/bhnd
Message-ID:  <201612192020.uBJKKY0O052377@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: landonf
Date: Mon Dec 19 20:20:33 2016
New Revision: 310292
URL: https://svnweb.freebsd.org/changeset/base/310292

Log:
  bhnd(4): support direct conversion of bhnd_nvram_val
  
  This adds support for bhnd_nvram_val_convert_init() and
  bhnd_nvram_val_convert_new(), which may be used to perform value
  format-aware encoding of an NVRAM value to a new target format/type.
  
  This will be used to simplify converting to/from serialized
  format-specific NVRAM value representations to common external
  representations.
  
  Approved by:	adrian (mentor)
  Differential Revision:	https://reviews.freebsd.org/D8757

Added:
  head/sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/nvram/bhnd_nvram.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
  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_subr.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_value.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_value.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h
  head/sys/modules/bhnd/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Dec 19 20:11:48 2016	(r310291)
+++ head/sys/conf/files	Mon Dec 19 20:20:33 2016	(r310292)
@@ -1247,6 +1247,7 @@ dev/bhnd/nvram/bhnd_nvram_subr.c	optiona
 dev/bhnd/nvram/bhnd_nvram_value.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_value_fmts.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_value_prf.c	optional bhnd
+dev/bhnd/nvram/bhnd_nvram_value_subr.c	optional bhnd
 dev/bhnd/nvram/bhnd_sprom.c		optional bhnd
 dev/bhnd/siba/siba.c			optional siba bhnd
 dev/bhnd/siba/siba_bhndb.c		optional siba bhnd bhndb

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram.h
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram.h	Mon Dec 19 20:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram.h	Mon Dec 19 20:20:33 2016	(r310292)
@@ -111,14 +111,16 @@ typedef enum {
 						     NUL-terminated strings */
 } bhnd_nvram_type;
 
-const char	*bhnd_nvram_string_array_next(const char *inp, size_t ilen,
-		     const char *prev); 
-
 bool		 bhnd_nvram_is_signed_type(bhnd_nvram_type type);
 bool		 bhnd_nvram_is_unsigned_type(bhnd_nvram_type type);
 bool		 bhnd_nvram_is_int_type(bhnd_nvram_type type);
 bool		 bhnd_nvram_is_array_type(bhnd_nvram_type type);
 bhnd_nvram_type	 bhnd_nvram_base_type(bhnd_nvram_type type);
 const char	*bhnd_nvram_type_name(bhnd_nvram_type type);
+size_t		 bhnd_nvram_type_width(bhnd_nvram_type type);
+size_t		 bhnd_nvram_type_host_align(bhnd_nvram_type type);
+
+const char	*bhnd_nvram_string_array_next(const char *inp, size_t ilen,
+		     const char *prev, size_t *olen); 
 
 #endif /* _BHND_NVRAM_BHND_NVRAM_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:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c	Mon Dec 19 20:20:33 2016	(r310292)
@@ -647,10 +647,8 @@ bhnd_nvram_bcm_getvar_ptr(struct bhnd_nv
 
 	/* Handle header variables */
 	if ((hvar = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep)) != NULL) {
-		BHND_NV_ASSERT(
-		    hvar->len % bhnd_nvram_value_size(hvar->type, NULL, 0,
-			hvar->nelem) == 0,
-		    ("length is not aligned to type width"));
+		BHND_NV_ASSERT(bhnd_nvram_value_check_aligned(&hvar->value,
+		    hvar->len, hvar->type) == 0, ("value misaligned"));
 
 		*type = hvar->type;
 		*len = hvar->len;

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:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c	Mon Dec 19 20:20:33 2016	(r310292)
@@ -597,7 +597,7 @@ bhnd_nvram_sprom_read_offset(struct bhnd
 	} sp_value;
 
 	/* Determine type width */
-	sp_width = bhnd_nvram_value_size(type, NULL, 0, 1);
+	sp_width = bhnd_nvram_type_width(type);
 	if (sp_width == 0) {
 		/* Variable-width types are unsupported */
 		BHND_NV_LOG("invalid %s SPROM offset type %d\n", var->name,
@@ -716,7 +716,7 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvra
 	var_btype = bhnd_nvram_base_type(var->type);
 
 	/* Calculate total byte length of the native encoding */
-	if ((iwidth = bhnd_nvram_value_size(var_btype, NULL, 0, 1)) == 0) {
+	if ((iwidth = bhnd_nvram_value_size(NULL, 0, var_btype, 1)) == 0) {
 		/* SPROM does not use (and we do not support) decoding of
 		 * variable-width data types */
 		BHND_NV_LOG("invalid SPROM data type: %d", var->type);
@@ -1219,7 +1219,7 @@ sprom_opcode_set_type(struct sprom_opcod
 	}
 
 	/* Fetch type width for use as our scale value */
-	width = bhnd_nvram_value_size(type, NULL, 0, 1);
+	width = bhnd_nvram_type_width(type);
 	if (width == 0) {
 		SPROM_OP_BAD(state, "unsupported variable-width type: %d\n",
 		    type);

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_private.h
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_private.h	Mon Dec 19 20:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_private.h	Mon Dec 19 20:20:33 2016	(r310292)
@@ -167,11 +167,15 @@ int				 bhnd_nvram_value_coerce(const vo
 				     void *outp, size_t *olen,
 				     bhnd_nvram_type otype);
 
-int				 bhnd_nvram_value_nelem(bhnd_nvram_type type,
-				     const void *data, size_t len,
+int				 bhnd_nvram_value_check_aligned(const void *inp,
+				     size_t ilen, bhnd_nvram_type itype);
+
+int				 bhnd_nvram_value_nelem(const void *inp,
+				     size_t ilen, bhnd_nvram_type itype,
 				     size_t *nelem);
-size_t				 bhnd_nvram_value_size(bhnd_nvram_type type,
-				     const void *data, size_t nbytes, 
+
+size_t				 bhnd_nvram_value_size(const void *inp,
+				     size_t ilen, bhnd_nvram_type itype,
 				     size_t nelem);
 
 int				 bhnd_nvram_value_printf(const char *fmt,
@@ -183,6 +187,10 @@ int				 bhnd_nvram_value_vprintf(const c
 				     bhnd_nvram_type itype, char *outp,
 				     size_t *olen, va_list ap);
 
+const void			*bhnd_nvram_value_array_next(const void *inp,
+				     size_t ilen, bhnd_nvram_type itype,
+				     const void *prev, size_t *olen);
+
 const struct bhnd_nvram_vardefn	*bhnd_nvram_find_vardefn(const char *varname);
 const struct bhnd_nvram_vardefn	*bhnd_nvram_get_vardefn(size_t id);
 size_t				 bhnd_nvram_get_vardefn_id(

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_store.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_store.c	Mon Dec 19 20:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_store.c	Mon Dec 19 20:20:33 2016	(r310292)
@@ -288,7 +288,7 @@ bhnd_nvram_store_setvar(struct bhnd_nvra
 
 	/* Verify buffer size alignment for the given type. If this is a
 	 * variable width type, a width of 0 will always pass this check */
-	if (len % bhnd_nvram_value_size(type, buf, len, 1) != 0)
+	if (len % bhnd_nvram_value_size(buf, len, type, 1) != 0)
 		return (EINVAL);
 
 	/* Determine string format (or directly add variable, if a C string) */

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c	Mon Dec 19 20:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c	Mon Dec 19 20:20:33 2016	(r310292)
@@ -71,12 +71,6 @@ __FBSDID("$FreeBSD$");
 MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data");
 #endif
 
-/** signed/unsigned 32-bit integer value storage */
-union bhnd_nvram_int_storage {
-	uint32_t	u32;
-	int32_t		s32;
-};
-
 /*
  * CRC-8 lookup table used to checksum SPROM and NVRAM data via
  * bhnd_nvram_crc8().
@@ -343,112 +337,44 @@ bhnd_nvram_base_type(bhnd_nvram_type typ
 }
 
 /**
- * Calculate the number of elements represented by a value of @p len bytes
- * with @p type.
- *
- * @param	type	The value type.
- * @param	data	The actual data to be queried, or NULL if unknown.
- * @param	len	The length in bytes of @p data, or if @p data is NULL,
- *			the expected length in bytes.
- * @param[out]	nelem	On success, the number of elements. If @p type is not
- *			a fixed width type (e.g. BHND_NVRAM_TYPE_STRING_ARRAY),
- *			and @p data is NULL, an @p nelem value of 0 will be
- *			returned.
- *
- * @retval 0		success
- * @retval EFTYPE	if @p type is not an array type, and @p len is not
- *			equal to the size of a single element of @p type.
- * @retval EFAULT	if @p len is not correctly aligned for elements of
- *			@p type.
+ * Return the size, in bytes, of a single element of @p type, or 0
+ * if @p type is a variable-width type.
+ * 
+ * @param type	The type to query.
  */
-int
-bhnd_nvram_value_nelem(bhnd_nvram_type type, const void *data, size_t len,
-    size_t *nelem)
+size_t
+bhnd_nvram_type_width(bhnd_nvram_type type)
 {
-	bhnd_nvram_type	base_type;
-	size_t		base_size;
-
-	/* Length must be aligned to the element size */
-	base_type = bhnd_nvram_base_type(type);
-	base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1);
-	if (base_size != 0 && len % base_size != 0)
-		return (EFAULT);
-
 	switch (type) {
 	case BHND_NVRAM_TYPE_STRING:
-	case BHND_NVRAM_TYPE_STRING_ARRAY: {
-		const char	*p;
-		size_t		 nleft;
-
-		/* Cannot determine the element count without parsing
-		 * the actual data */
-		if (data == NULL) {
-			*nelem = 0;
-			return (0);
-		}
-
-		/* Iterate over the NUL-terminated strings to calculate
-		 * total element count */
-		p = data;
-		nleft = len;
-		*nelem = 0;
-		while (nleft > 0) {
-			size_t slen;
-
-			/* Increment element count */
-			(*nelem)++;
-
-			/* If not a string array, data must not contain more
-			 * than one entry. */
-			if (!bhnd_nvram_is_array_type(type) && *nelem > 1)
-				return (EFTYPE);
-
-			/* Determine string length */
-			slen = strnlen(p, nleft);
-			nleft -= slen;
-	
-			/* Advance input */
-			p += slen;
-
-			/* Account for trailing NUL, if we haven't hit the end
-			 * of the input */
-			if (nleft > 0) {
-				nleft--;
-				p++;
-			}
-		}
-
-		return (0);
-	}
-	case BHND_NVRAM_TYPE_INT8:
-	case BHND_NVRAM_TYPE_UINT8:
-	case BHND_NVRAM_TYPE_CHAR:
-	case BHND_NVRAM_TYPE_INT16:
-	case BHND_NVRAM_TYPE_UINT16:
-	case BHND_NVRAM_TYPE_INT32:
-	case BHND_NVRAM_TYPE_UINT32:
-	case BHND_NVRAM_TYPE_INT64:
-	case BHND_NVRAM_TYPE_UINT64:
-		/* Length must be equal to the size of exactly one
-		 * element (arrays can represent zero elements -- non-array
-		 * types cannot) */
-		if (len != base_size)
-			return (EFTYPE);
-		*nelem = 1;
+	case BHND_NVRAM_TYPE_STRING_ARRAY:
 		return (0);
 
+	case BHND_NVRAM_TYPE_CHAR:
+	case BHND_NVRAM_TYPE_CHAR_ARRAY:
+	case BHND_NVRAM_TYPE_UINT8:
 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
-	case BHND_NVRAM_TYPE_UINT16_ARRAY:
-	case BHND_NVRAM_TYPE_UINT32_ARRAY:
-	case BHND_NVRAM_TYPE_UINT64_ARRAY:
+	case BHND_NVRAM_TYPE_INT8:
 	case BHND_NVRAM_TYPE_INT8_ARRAY:
+		return (sizeof(uint8_t));
+
+	case BHND_NVRAM_TYPE_UINT16:
+	case BHND_NVRAM_TYPE_UINT16_ARRAY:
+	case BHND_NVRAM_TYPE_INT16:
 	case BHND_NVRAM_TYPE_INT16_ARRAY:
+		return (sizeof(uint16_t));
+
+	case BHND_NVRAM_TYPE_UINT32:
+	case BHND_NVRAM_TYPE_UINT32_ARRAY:
+	case BHND_NVRAM_TYPE_INT32:
 	case BHND_NVRAM_TYPE_INT32_ARRAY:
+		return (sizeof(uint32_t));
+
+	case BHND_NVRAM_TYPE_UINT64:
+	case BHND_NVRAM_TYPE_UINT64_ARRAY:
+	case BHND_NVRAM_TYPE_INT64:
 	case BHND_NVRAM_TYPE_INT64_ARRAY:
-	case BHND_NVRAM_TYPE_CHAR_ARRAY:
-		BHND_NV_ASSERT(base_size != 0, ("invalid base size"));
-		*nelem = len / base_size;
-		return (0);
+		return (sizeof(uint64_t));
 	}
 
 	/* Quiesce gcc4.2 */
@@ -456,130 +382,43 @@ bhnd_nvram_value_nelem(bhnd_nvram_type t
 }
 
 /**
- * Return the size, in bytes, of a value of @p type with @p nelem elements.
+ * Return the native host alignment for values of @p type.
  * 
- * @param	type	The value type.
- * @param	data	The actual data to be queried, or NULL if unknown. If
- *			NULL and the base type is not a fixed width type
- *			(e.g. BHND_NVRAM_TYPE_STRING), 0 will be returned.
- * @param	nbytes	The size of @p data, in bytes, or 0 if @p data is NULL.
- * @param	nelem	The number of elements. If @p type is not an array type,
- *			this value must be 1.
- * 
- * @retval 0		If @p type has a variable width, and @p data is NULL.
- * @retval 0		If a @p nelem value greater than 1 is provided for a
- *			non-array @p type.
- * @retval 0		If a @p nelem value of 0 is provided.
- * @retval 0		If the result would exceed the maximum value
- *			representable by size_t.
- * @retval non-zero	The size, in bytes, of @p type with @p nelem elements.
+ * @param type The type to query.
  */
 size_t
-bhnd_nvram_value_size(bhnd_nvram_type type, const void *data, size_t nbytes,
-    size_t nelem)
+bhnd_nvram_type_host_align(bhnd_nvram_type type)
 {
-	/* If nelem 0, nothing to do */
-	if (nelem == 0)
-		return (0);
-
-	/* Non-array types must have an nelem value of 1 */
-	if (!bhnd_nvram_is_array_type(type) && nelem != 1)
-		return (0);
-
 	switch (type) {
+	case BHND_NVRAM_TYPE_CHAR:
+	case BHND_NVRAM_TYPE_CHAR_ARRAY:
+	case BHND_NVRAM_TYPE_STRING:
+	case BHND_NVRAM_TYPE_STRING_ARRAY:
+		return (_Alignof(uint8_t));
+	case BHND_NVRAM_TYPE_UINT8:
 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
+		return (_Alignof(uint8_t));
+	case BHND_NVRAM_TYPE_UINT16:
 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
+		return (_Alignof(uint16_t));
+	case BHND_NVRAM_TYPE_UINT32:
 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
+		return (_Alignof(uint32_t));
+	case BHND_NVRAM_TYPE_UINT64:
 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
-	case BHND_NVRAM_TYPE_INT8_ARRAY:
-	case BHND_NVRAM_TYPE_INT16_ARRAY:
-	case BHND_NVRAM_TYPE_INT32_ARRAY:
-	case BHND_NVRAM_TYPE_INT64_ARRAY:
-	case BHND_NVRAM_TYPE_CHAR_ARRAY: {
-		bhnd_nvram_type	base_type;
-		size_t		base_size;
-
-		base_type = bhnd_nvram_base_type(type);
-		base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1);
-
-		/* Would nelem * base_size overflow? */
-		if (SIZE_MAX / nelem < base_size) {
-			BHND_NV_LOG("cannot represent size %s * %zu\n",
-			    bhnd_nvram_type_name(base_type), nelem);
-			return (0);
-		}
-
-		return (nelem * base_size);
-	}
-
-	case BHND_NVRAM_TYPE_STRING_ARRAY: {
-		const char	*p;
-		size_t		 total_size;
-
-		if (data == NULL)
-			return (0);
-
-		/* Iterate over the NUL-terminated strings to calculate
-		 * total byte length */
-		p = data;
-		total_size = 0;
-		for (size_t i = 0; i < nelem; i++) {
-			size_t	elem_size;
-
-			elem_size = strnlen(p, nbytes - total_size);
-			p += elem_size;
-
-			/* Check for (and skip) terminating NUL */
-			if (total_size < nbytes && *p == '\0') {
-				elem_size++;
-				p++;
-			}
-
-			/* Would total_size + elem_size overflow?
-			 * 
-			 * A memory range larger than SIZE_MAX shouldn't be,
-			 * possible, but include the check for completeness */
-			if (SIZE_MAX - total_size < elem_size)
-				return (0);
-
-			total_size += elem_size;
-		}
-
-		return (total_size);
-	}
-
-	case BHND_NVRAM_TYPE_STRING: {
-		size_t size;
-
-		if (data == NULL)
-			return (0);
-
-		/* Find length */
-		size = strnlen(data, nbytes);
-
-		/* Is there a terminating NUL, or did we just hit the
-		 * end of the string input */
-		if (size < nbytes)
-			size++;
-
-		return (size);
-	}
+		return (_Alignof(uint64_t));
 	case BHND_NVRAM_TYPE_INT8:
-	case BHND_NVRAM_TYPE_UINT8:
-	case BHND_NVRAM_TYPE_CHAR:
-		return (sizeof(uint8_t));
-
+	case BHND_NVRAM_TYPE_INT8_ARRAY:
+		return (_Alignof(int8_t));
 	case BHND_NVRAM_TYPE_INT16:
-	case BHND_NVRAM_TYPE_UINT16:
-		return (sizeof(uint16_t));
-
+	case BHND_NVRAM_TYPE_INT16_ARRAY:
+		return (_Alignof(int16_t));
 	case BHND_NVRAM_TYPE_INT32:
-	case BHND_NVRAM_TYPE_UINT32:
-		return (sizeof(uint32_t));
-
-	case BHND_NVRAM_TYPE_UINT64:
+	case BHND_NVRAM_TYPE_INT32_ARRAY:
+		return (_Alignof(int32_t));
 	case BHND_NVRAM_TYPE_INT64:
-		return (sizeof(uint64_t));
+	case BHND_NVRAM_TYPE_INT64_ARRAY:
+		return (_Alignof(int64_t));
 	}
 
 	/* Quiesce gcc4.2 */
@@ -587,132 +426,30 @@ bhnd_nvram_value_size(bhnd_nvram_type ty
 }
 
 /**
- * Iterate over all strings in the @p inp string array.
+ * Iterate over all strings in the @p inp string array (@see
+ * BHNF_NVRAM_TYPE_STRING_ARRAY).
  *
- * @param	inp	The string array to be iterated. This must be a buffer
- *			of one or more NUL-terminated strings --
- *			@see BHND_NVRAM_TYPE_STRING_ARRAY.
- * @param	ilen	The size, in bytes, of @p inp, including any
- *			terminating NUL character(s).
- * @param	prev	The value previously returned by
- *			bhnd_nvram_string_array_next(), or NULL to begin
- *			iteration.
+ * @param		inp	The string array to be iterated. This must be a
+ *				buffer of one or more NUL-terminated strings.
+ * @param		ilen	The size, in bytes, of @p inp, including any
+ *				terminating NUL character(s).
+ * @param		prev	The pointer previously returned by
+ *				bhnd_nvram_string_array_next(), or NULL to begin
+ *				iteration.
+* @param[in,out]	olen	If @p prev is non-NULL, @p olen must be a
+ *				pointer to the length previously returned by
+ *				bhnd_nvram_string_array_next(). On success, will
+ *				be set to the next element's length, in bytes.
  *
  * @retval non-NULL	A reference to the next NUL-terminated string
  * @retval NULL		If the end of the string array is reached.
  */
 const char *
-bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev)
+bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev,
+    size_t *olen)
 {
-	size_t nremain, plen;
-
-	if (ilen == 0)
-		return (NULL);
-
-	if (prev == NULL)
-		return (inp);
-
-	/* Advance to next value */
-	BHND_NV_ASSERT(prev >= inp, ("invalid prev pointer"));
-	BHND_NV_ASSERT(prev < (inp+ilen), ("invalid prev pointer"));
-
-	nremain = ilen - (size_t)(prev - inp);
-	plen = strnlen(prev, nremain);
-	nremain -= plen;
-
-	/* Only a trailing NUL remains? */
-	if (nremain <= 1)
-		return (NULL);
-
-	return (prev + plen + 1);
-}
-
-/**
- * Format a string representation of @p inp using @p fmt, with, writing the
- * result to @p outp.
- *
- * Refer to bhnd_nvram_val_vprintf() for full format string documentation.
- *
- * @param		fmt	The format string.
- * @param		inp	The value to be formatted.
- * @param		ilen	The size of @p inp, in bytes.
- * @param		itype	The type of @p inp.
- * @param[out]		outp	On success, the string value will be written to
- *				this buffer. This argment may be NULL if the
- *				value is not desired.
- * @param[in,out]	olen	The capacity of @p outp. On success, will be set
- *				to the actual size of the formatted string.
- *
- * @retval 0		success
- * @retval EINVAL	If @p fmt contains unrecognized format string
- *			specifiers.
- * @retval ENOMEM	If the @p outp is non-NULL, and the provided @p olen
- *			is too small to hold the encoded value.
- * @retval EFTYPE	If value coercion from @p inp to a string value via
- *			@p fmt is unsupported.
- * @retval ERANGE	If value coercion of @p value would overflow (or
- *			underflow) the representation defined by @p fmt.
- */
-int
-bhnd_nvram_value_printf(const char *fmt, const void *inp, size_t ilen,
-    bhnd_nvram_type itype, char *outp, size_t *olen, ...)
-{
-	va_list	ap;
-	int	error;
-
-	va_start(ap, olen);
-	error = bhnd_nvram_value_vprintf(fmt, inp, ilen, itype, outp, olen, ap);
-	va_end(ap);
-
-	return (error);
-}
-
-/**
- * Format a string representation of @p inp using @p fmt, with, writing the
- * result to @p outp.
- *
- * Refer to bhnd_nvram_val_vprintf() for full format string documentation.
- *
- * @param		fmt	The format string.
- * @param		inp	The value to be formatted.
- * @param		ilen	The size of @p inp, in bytes.
- * @param		itype	The type of @p inp.
- * @param[out]		outp	On success, the string value will be written to
- *				this buffer. This argment may be NULL if the
- *				value is not desired.
- * @param[in,out]	olen	The capacity of @p outp. On success, will be set
- *				to the actual size of the formatted string.
- * @param		ap	Argument list.
- *
- * @retval 0		success
- * @retval EINVAL	If @p fmt contains unrecognized format string
- *			specifiers.
- * @retval ENOMEM	If the @p outp is non-NULL, and the provided @p olen
- *			is too small to hold the encoded value.
- * @retval EFTYPE	If value coercion from @p inp to a string value via
- *			@p fmt is unsupported.
- * @retval ERANGE	If value coercion of @p value would overflow (or
- *			underflow) the representation defined by @p fmt.
- */
-int
-bhnd_nvram_value_vprintf(const char *fmt, const void *inp, size_t ilen,
-    bhnd_nvram_type itype, char *outp, size_t *olen, va_list ap)
-{
-	bhnd_nvram_val	val;
-	int		error;
-
-	/* Map input buffer as a value instance */
-	error = bhnd_nvram_val_init(&val, NULL, inp, ilen, itype,
-	    BHND_NVRAM_VAL_BORROW_DATA);
-	if (error)
-		return (error);
-
-	/* Attempt to format the value */
-	error = bhnd_nvram_val_vprintf(&val, fmt, outp, olen, ap);
-
-	/* Clean up */
-	bhnd_nvram_val_release(&val);
-	return (error);
+	return (bhnd_nvram_value_array_next(inp, ilen,
+	    BHND_NVRAM_TYPE_STRING_ARRAY, prev, olen));
 }
 
 /* used by bhnd_nvram_find_vardefn() */
@@ -825,47 +562,6 @@ bhnd_nvram_validate_name(const char *nam
 }
 
 /**
- * Coerce value @p inp of type @p itype to @p otype, writing the
- * result to @p outp.
- *
- * @param		inp	The value to be coerced.
- * @param		ilen	The size of @p inp, in bytes.
- * @param		itype	The base data type of @p inp.
- * @param[out]		outp	On success, the value will be written to this 
- *				buffer. This argment may be NULL if the value
- *				is not desired.
- * @param[in,out]	olen	The capacity of @p outp. On success, will be set
- *				to the actual size of the requested value.
- * @param		otype	The data type to be written to @p outp.
- *
- * @retval 0		success
- * @retval ENOMEM	If @p outp is non-NULL and a buffer of @p olen is too
- *			small to hold the requested value.
- * @retval EFTYPE	If the variable data cannot be coerced to @p otype.
- * @retval ERANGE	If value coercion would overflow @p otype.
- */
-int
-bhnd_nvram_value_coerce(const void *inp, size_t ilen, bhnd_nvram_type itype,
-    void *outp, size_t *olen, bhnd_nvram_type otype)
-{
-	bhnd_nvram_val	val;
-	int		error;
-
-	/* Wrap input buffer in a value instance */
-	error = bhnd_nvram_val_init(&val, NULL, inp, ilen,
-	    itype, BHND_NVRAM_VAL_BORROW_DATA|BHND_NVRAM_VAL_FIXED);
-	if (error)
-		return (error);
-
-	/* Try to encode as requested type */
-	error = bhnd_nvram_val_encode(&val, outp, olen, otype);
-
-	/* Clean up and return error */
-	bhnd_nvram_val_release(&val);
-	return (error);
-}
-
-/**
  * Parses the string in the optionally NUL-terminated @p str to as an integer
  * value of @p otype, accepting any integer format supported by the standard
  * strtoul().
@@ -1114,7 +810,7 @@ bhnd_nvram_parse_int(const char *str, si
 		value = -value;
 
 	/* Provide (and verify) required length */
-	*olen = bhnd_nvram_value_size(otype, NULL, 0, 1);
+	*olen = bhnd_nvram_type_width(otype);
 	if (outp == NULL)
 		return (0);
 	else if (limit < *olen)

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_value.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_value.c	Mon Dec 19 20:11:48 2016	(r310291)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_value.c	Mon Dec 19 20:20:33 2016	(r310292)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 
 #ifdef _KERNEL
 
+#include <sys/ctype.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/systm.h>
@@ -43,6 +44,7 @@ __FBSDID("$FreeBSD$");
 
 #else /* !_KERNEL */
 
+#include <ctype.h>
 #include <inttypes.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -54,6 +56,8 @@ __FBSDID("$FreeBSD$");
 
 #include "bhnd_nvram_valuevar.h"
 
+static int	 bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
+		     const void *inp, size_t ilen, bhnd_nvram_type itype);
 
 static void	*bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
 		     bhnd_nvram_type itype, uint32_t flags);
@@ -62,6 +66,15 @@ static int	 bhnd_nvram_val_set(bhnd_nvra
 static int	 bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
 		     const void *inp, size_t ilen, bhnd_nvram_type itype);
 
+static int	 bhnd_nvram_val_encode_int(const void *inp, size_t ilen,
+		     bhnd_nvram_type itype, void *outp, size_t *olen,
+		     bhnd_nvram_type otype);
+static int	 bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
+		     bhnd_nvram_type itype, void *outp, size_t *olen,
+		     bhnd_nvram_type otype);
+
+/** Initialize an empty value instance with @p _fmt, @p _storage, and
+ *  an implicit callee-owned reference */
 #define	BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage)		\
 	(bhnd_nvram_val) {					\
 		.refs = 1,					\
@@ -80,6 +93,156 @@ static int	 bhnd_nvram_val_set_inline(bh
 	    value->data.ptr == NULL,				\
 	    ("previously initialized value"))
 
+/** Return true if BHND_NVRAM_VAL_BORROW_DATA or BHND_NVRAM_VAL_STATIC_DATA is
+ *  set in @p _flags (e.g. we should attempt to directly reference external
+ *  data */
+#define	BHND_NVRAM_VAL_EXTREF_BORROWED_DATA(_flags)		\
+	(((_flags) & BHND_NVRAM_VAL_BORROW_DATA) ||		\
+	 ((_flags) & BHND_NVRAM_VAL_STATIC_DATA))
+
+/** Flags permitted when performing val-based initialization via
+ *  bhnd_nvram_val_convert_init() or bhnd_nvram_val_convert_new() */
+#define	BHND_NVRAM_VALID_CONV_FLAGS	\
+	(BHND_NVRAM_VAL_FIXED |		\
+	 BHND_NVRAM_VAL_DYNAMIC |	\
+	 BHND_NVRAM_VAL_COPY_DATA)
+
+/** Returns true if @p _val must be copied in bhnd_nvram_val_copy(), false
+ *  if its reference count may be safely incremented */
+#define	BHND_NVRAM_VAL_NEED_COPY(_val)				\
+	((_val)->val_storage == BHND_NVRAM_VAL_STORAGE_AUTO ||	\
+	 (_val)->data_storage == BHND_NVRAM_VAL_DATA_EXT_WEAK)
+
+volatile u_int			 refs;		/**< reference count */
+bhnd_nvram_val_storage		 val_storage;	/**< value structure storage */
+const bhnd_nvram_val_fmt	*fmt;		/**< value format */
+bhnd_nvram_val_data_storage	 data_storage;	/**< data storage */
+bhnd_nvram_type			 data_type;	/**< data type */
+size_t				 data_len;	/**< data size */
+
+/**
+ * Return the human-readable name of @p fmt.
+ */
+const char *
+bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt *fmt)
+{
+	return (fmt->name);
+}
+
+/**
+ * Return the default format for values of @p type.
+ */
+const bhnd_nvram_val_fmt *
+bhnd_nvram_val_default_fmt(bhnd_nvram_type type)
+{
+	switch (type) {
+	case BHND_NVRAM_TYPE_UINT8:
+		return (&bhnd_nvram_val_uint8_fmt);
+	case BHND_NVRAM_TYPE_UINT16:
+		return (&bhnd_nvram_val_uint16_fmt);
+	case BHND_NVRAM_TYPE_UINT32:
+		return (&bhnd_nvram_val_uint32_fmt);
+	case BHND_NVRAM_TYPE_UINT64:
+		return (&bhnd_nvram_val_uint64_fmt);
+	case BHND_NVRAM_TYPE_INT8:
+		return (&bhnd_nvram_val_int8_fmt);
+	case BHND_NVRAM_TYPE_INT16:
+		return (&bhnd_nvram_val_int16_fmt);
+	case BHND_NVRAM_TYPE_INT32:
+		return (&bhnd_nvram_val_int32_fmt);
+	case BHND_NVRAM_TYPE_INT64:
+		return (&bhnd_nvram_val_int64_fmt);
+	case BHND_NVRAM_TYPE_CHAR:
+		return (&bhnd_nvram_val_char_fmt);
+	case BHND_NVRAM_TYPE_STRING:
+		return (&bhnd_nvram_val_string_fmt);
+	case BHND_NVRAM_TYPE_UINT8_ARRAY:
+		return (&bhnd_nvram_val_uint8_array_fmt);
+	case BHND_NVRAM_TYPE_UINT16_ARRAY:
+		return (&bhnd_nvram_val_uint16_array_fmt);
+	case BHND_NVRAM_TYPE_UINT32_ARRAY:
+		return (&bhnd_nvram_val_uint32_array_fmt);
+	case BHND_NVRAM_TYPE_UINT64_ARRAY:
+		return (&bhnd_nvram_val_uint64_array_fmt);
+	case BHND_NVRAM_TYPE_INT8_ARRAY:
+		return (&bhnd_nvram_val_int8_array_fmt);
+	case BHND_NVRAM_TYPE_INT16_ARRAY:
+		return (&bhnd_nvram_val_int16_array_fmt);
+	case BHND_NVRAM_TYPE_INT32_ARRAY:
+		return (&bhnd_nvram_val_int32_array_fmt);
+	case BHND_NVRAM_TYPE_INT64_ARRAY:
+		return (&bhnd_nvram_val_int64_array_fmt);
+	case BHND_NVRAM_TYPE_CHAR_ARRAY:
+		return (&bhnd_nvram_val_char_array_fmt);
+	case BHND_NVRAM_TYPE_STRING_ARRAY:
+		return (&bhnd_nvram_val_string_array_fmt);
+	}
+	
+	/* Quiesce gcc4.2 */
+	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
+}
+
+/**
+ * Determine whether @p fmt (or new format delegated to by @p fmt) is
+ * capable of direct initialization from buffer @p inp.
+ * 
+ * @param[in,out]	fmt	Indirect pointer to the NVRAM value format. If
+ *				the format instance cannot handle the data type
+ *				directly, it may delegate to a new format
+ *				instance. On success, this parameter will be
+ *				set to the format that should be used when
+ *				performing initialization from @p inp.
+ * @param		inp	Input data.
+ * @param		ilen	Input data length.
+ * @param		itype	Input data type.
+ *
+ * @retval 0		If initialization from @p inp is supported.
+ * @retval EFTYPE	If initialization from @p inp is unsupported.
+ * @retval EFAULT	if @p ilen is not correctly aligned for elements of
+ *			@p itype.
+ */
+static int
+bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
+    size_t ilen, bhnd_nvram_type itype)
+{
+	const bhnd_nvram_val_fmt	*ofmt, *nfmt;
+	int				 error;
+
+	nfmt = ofmt = *fmt;
+
+	/* Validate alignment */
+	if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
+		return (error);
+
+	/* If the format does not provide a filter function, it only supports
+	 * direct initialization from its native type */
+	if (ofmt->op_filter == NULL) {
+		if (itype == ofmt->native_type)
+			return (0);
+
+		return (EFTYPE);
+	}
+
+	/* Use the filter function to determine whether direct initialization
+	 * from itype is permitted */
+	error = ofmt->op_filter(&nfmt, inp, ilen, itype);
+	if (error)
+		return (error);
+
+	/* Retry filter with new format? */
+	if (ofmt != nfmt) {
+		error = bhnd_nvram_val_fmt_filter(&nfmt, inp, ilen, itype);
+		if (error)
+			return (error);
+
+		/* Success -- provide delegated format to caller */
+		*fmt = nfmt;
+	}
+
+	/* Value can be initialized with provided format and input type */
+	return (0);
+}
+
 /* Common initialization support for bhnd_nvram_val_init() and
  * bhnd_nvram_val_new() */
 static int
@@ -92,35 +255,20 @@ bhnd_nvram_val_init_common(bhnd_nvram_va
 	size_t		 olen;
 	int		 error;
 
+	/* If the value format is unspecified, we use the default format
+	 * for the input data type */
+	if (fmt == NULL)
+		fmt = bhnd_nvram_val_default_fmt(itype);
+
 	/* Determine expected data type, and allow the format to delegate to
 	 * a new format instance */
-	if (fmt != NULL && fmt->op_filter != NULL) {
-		const bhnd_nvram_val_fmt *nfmt = fmt;
-
-		/* Use the filter function to determine whether direct
-		 * initialization from is itype permitted */
-		error = fmt->op_filter(&nfmt, inp, ilen, itype);
-		if (error)
-			return (error);
-
-		/* Retry initialization with new format? */
-		if (nfmt != fmt) {
-			return (bhnd_nvram_val_init_common(value, val_storage,
-			    nfmt, inp, ilen, itype, flags));
-		}
-
-		/* Value can be initialized with provided input type */
-		otype = itype;
-
-	} else if (fmt != NULL) {
-		/* Value must be initialized with the format's native
-		 * type */
+	if ((error = bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype))) {
+		/* Direct initialization from the provided input type is
+		 * not supported; alue must be initialized with the format's
+		 * native type */
 		otype = fmt->native_type;
-
 	} else {
-		/* No format specified; we can initialize directly from the
-		 * input data, and we'll handle all format operations
-		 * internally. */
+		/* Value can be initialized with provided input type */
 		otype = itype;
 	}
 
@@ -236,6 +384,145 @@ bhnd_nvram_val_new(bhnd_nvram_val **valu
 	return (error);
 }
 
+
+/* Common initialization support for bhnd_nvram_val_convert_init() and
+ * bhnd_nvram_val_convert_new() */
+static int
+bhnd_nvram_val_convert_common(bhnd_nvram_val *value,
+    bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
+    bhnd_nvram_val *src, uint32_t flags)
+{
+	const void	*inp;
+	void		*outp;
+	bhnd_nvram_type	 itype, otype;
+	size_t		 ilen, olen;
+	int		 error;
+
+	/* Determine whether direct initialization from the source value's
+	 * existing data type is supported by the new format */
+	inp = bhnd_nvram_val_bytes(src, &ilen, &itype);
+	if (bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype) == 0) {
+		/* Adjust value flags based on the source data storage */
+		switch (src->data_storage) {
+		case BHND_NVRAM_VAL_DATA_NONE:
+		case BHND_NVRAM_VAL_DATA_INLINE:
+		case BHND_NVRAM_VAL_DATA_EXT_WEAK:
+		case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
+			break;
+
+		case BHND_NVRAM_VAL_DATA_EXT_STATIC:
+			/* If the source data has static storage duration,
+			 * we should apply that transitively */
+			if (flags & BHND_NVRAM_VAL_BORROW_DATA)
+				flags |= BHND_NVRAM_VAL_STATIC_DATA;
+
+			break;
+		}
+
+		/* Delegate to standard initialization */
+		return (bhnd_nvram_val_init_common(value, val_storage, fmt, inp,
+		    ilen, itype, flags));
+	} 
+
+	/* Value must be initialized with the format's native type */
+	otype = fmt->native_type;
+
+	/* Initialize value instance */
+	*value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
+
+	/* Determine size when encoded in native format */
+	if ((error = bhnd_nvram_val_encode(src, NULL, &olen, otype)))
+		return (error);
+	
+	/* Fetch reference to (or allocate) an appropriately sized buffer */
+	outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
+	if (outp == NULL)
+		return (ENOMEM);
+	
+	/* Perform encode */
+	if ((error = bhnd_nvram_val_encode(src, outp, &olen, otype)))
+		return (error);
+
+	return (0);
+}
+
+/**
+ * Initialize an externally allocated instance of @p value with @p fmt, and
+ * attempt to initialize its internal representation from the given @p src
+ * value.
+ *
+ * On success, the caller owns a reference to @p value, and is responsible for
+ * freeing any resources allocated for @p value via bhnd_nvram_val_release().
+ *
+ * @param	value	The externally allocated value instance to be
+ *			initialized.
+ * @param	fmt	The value's format.
+ * @param	src	Input value to be converted.
+ * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
+ * 
+ * @retval 0		success
+ * @retval ENOMEM	If allocation fails.
+ * @retval EFTYPE	If @p fmt initialization from @p src is unsupported.
+ * @retval EFAULT	if @p ilen is not correctly aligned for elements of
+ *			@p itype.
+ * @retval ERANGE	If value coercion of @p src would overflow
+ *			(or underflow) the @p fmt representation.
+ */
+int
+bhnd_nvram_val_convert_init(bhnd_nvram_val *value,
+    const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
+{
+	int error;
+
+	error = bhnd_nvram_val_convert_common(value,
+	    BHND_NVRAM_VAL_STORAGE_AUTO, fmt, src, flags);
+	if (error)
+		bhnd_nvram_val_release(value);
+
+	return (error);
+}
+
+/**
+ * Allocate a value instance with @p fmt, and attempt to initialize its internal
+ * representation from the given @p src value.
+ *
+ * On success, the caller owns a reference to @p value, and is responsible for
+ * freeing any resources allocated for @p value via bhnd_nvram_val_release().
+ *
+ * @param[out]	value	On success, the allocated value instance.
+ * @param	fmt	The value's format.
+ * @param	src	Input value to be converted.
+ * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
+ * 
+ * @retval 0		success
+ * @retval ENOMEM	If allocation fails.
+ * @retval EFTYPE	If @p fmt initialization from @p src is unsupported.

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612192020.uBJKKY0O052377>