xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_value.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
177cb4d3eSLandon J. Fuller /*-
277cb4d3eSLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
377cb4d3eSLandon J. Fuller  * All rights reserved.
477cb4d3eSLandon J. Fuller  *
577cb4d3eSLandon J. Fuller  * Redistribution and use in source and binary forms, with or without
677cb4d3eSLandon J. Fuller  * modification, are permitted provided that the following conditions
777cb4d3eSLandon J. Fuller  * are met:
877cb4d3eSLandon J. Fuller  * 1. Redistributions of source code must retain the above copyright
977cb4d3eSLandon J. Fuller  *    notice, this list of conditions and the following disclaimer,
1077cb4d3eSLandon J. Fuller  *    without modification.
1177cb4d3eSLandon J. Fuller  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1277cb4d3eSLandon J. Fuller  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1377cb4d3eSLandon J. Fuller  *    redistribution must be conditioned upon including a substantially
1477cb4d3eSLandon J. Fuller  *    similar Disclaimer requirement for further binary redistribution.
1577cb4d3eSLandon J. Fuller  *
1677cb4d3eSLandon J. Fuller  * NO WARRANTY
1777cb4d3eSLandon J. Fuller  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1877cb4d3eSLandon J. Fuller  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1977cb4d3eSLandon J. Fuller  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2077cb4d3eSLandon J. Fuller  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2177cb4d3eSLandon J. Fuller  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2277cb4d3eSLandon J. Fuller  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2377cb4d3eSLandon J. Fuller  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2477cb4d3eSLandon J. Fuller  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2577cb4d3eSLandon J. Fuller  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2677cb4d3eSLandon J. Fuller  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2777cb4d3eSLandon J. Fuller  * THE POSSIBILITY OF SUCH DAMAGES.
2877cb4d3eSLandon J. Fuller  */
2977cb4d3eSLandon J. Fuller 
3077cb4d3eSLandon J. Fuller #include <sys/param.h>
3191898857SMark Johnston #include <sys/limits.h>
3277cb4d3eSLandon J. Fuller #include <sys/sbuf.h>
3377cb4d3eSLandon J. Fuller 
3477cb4d3eSLandon J. Fuller #ifdef _KERNEL
3577cb4d3eSLandon J. Fuller 
369be0790dSLandon J. Fuller #include <sys/ctype.h>
3777cb4d3eSLandon J. Fuller #include <sys/kernel.h>
3877cb4d3eSLandon J. Fuller #include <sys/malloc.h>
3977cb4d3eSLandon J. Fuller #include <sys/systm.h>
4077cb4d3eSLandon J. Fuller 
4177cb4d3eSLandon J. Fuller #include <machine/_inttypes.h>
4277cb4d3eSLandon J. Fuller 
4377cb4d3eSLandon J. Fuller #else /* !_KERNEL */
4477cb4d3eSLandon J. Fuller 
459be0790dSLandon J. Fuller #include <ctype.h>
4677cb4d3eSLandon J. Fuller #include <inttypes.h>
4777cb4d3eSLandon J. Fuller #include <errno.h>
4877cb4d3eSLandon J. Fuller #include <stdlib.h>
4977cb4d3eSLandon J. Fuller #include <string.h>
5077cb4d3eSLandon J. Fuller 
5177cb4d3eSLandon J. Fuller #endif /* _KERNEL */
5277cb4d3eSLandon J. Fuller 
5377cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
5477cb4d3eSLandon J. Fuller 
5577cb4d3eSLandon J. Fuller #include "bhnd_nvram_valuevar.h"
5677cb4d3eSLandon J. Fuller 
579be0790dSLandon J. Fuller static int	 bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
589be0790dSLandon J. Fuller 		     const void *inp, size_t ilen, bhnd_nvram_type itype);
5977cb4d3eSLandon J. Fuller 
6058efe686SLandon J. Fuller static void	*bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
6158efe686SLandon J. Fuller 		     bhnd_nvram_type itype, uint32_t flags);
6258efe686SLandon J. Fuller static int	 bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp,
6358efe686SLandon J. Fuller 		     size_t ilen, bhnd_nvram_type itype, uint32_t flags);
6458efe686SLandon J. Fuller static int	 bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
6577cb4d3eSLandon J. Fuller 		     const void *inp, size_t ilen, bhnd_nvram_type itype);
6677cb4d3eSLandon J. Fuller 
676cffadf0SLandon J. Fuller static int	 bhnd_nvram_val_encode_data(const void *inp, size_t ilen,
686cffadf0SLandon J. Fuller 		     bhnd_nvram_type itype, void *outp, size_t *olen,
696cffadf0SLandon J. Fuller 		     bhnd_nvram_type otype);
709be0790dSLandon J. Fuller static int	 bhnd_nvram_val_encode_int(const void *inp, size_t ilen,
719be0790dSLandon J. Fuller 		     bhnd_nvram_type itype, void *outp, size_t *olen,
729be0790dSLandon J. Fuller 		     bhnd_nvram_type otype);
736cffadf0SLandon J. Fuller static int	 bhnd_nvram_val_encode_null(const void *inp, size_t ilen,
746cffadf0SLandon J. Fuller 		     bhnd_nvram_type itype, void *outp, size_t *olen,
756cffadf0SLandon J. Fuller 		     bhnd_nvram_type otype);
766cffadf0SLandon J. Fuller static int	 bhnd_nvram_val_encode_bool(const void *inp, size_t ilen,
776cffadf0SLandon J. Fuller 		     bhnd_nvram_type itype, void *outp, size_t *olen,
786cffadf0SLandon J. Fuller 		     bhnd_nvram_type otype);
799be0790dSLandon J. Fuller static int	 bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
809be0790dSLandon J. Fuller 		     bhnd_nvram_type itype, void *outp, size_t *olen,
819be0790dSLandon J. Fuller 		     bhnd_nvram_type otype);
829be0790dSLandon J. Fuller 
839be0790dSLandon J. Fuller /** Initialize an empty value instance with @p _fmt, @p _storage, and
849be0790dSLandon J. Fuller  *  an implicit callee-owned reference */
8577cb4d3eSLandon J. Fuller #define	BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage)		\
8658efe686SLandon J. Fuller 	(bhnd_nvram_val) {					\
8777cb4d3eSLandon J. Fuller 		.refs = 1,					\
8877cb4d3eSLandon J. Fuller 		.val_storage = _storage,			\
8977cb4d3eSLandon J. Fuller 		.fmt = _fmt,					\
9077cb4d3eSLandon J. Fuller 		.data_storage = BHND_NVRAM_VAL_DATA_NONE,	\
9177cb4d3eSLandon J. Fuller 	};
9277cb4d3eSLandon J. Fuller 
9377cb4d3eSLandon J. Fuller /** Assert that @p value's backing representation state has initialized
9477cb4d3eSLandon J. Fuller  *  as empty. */
9577cb4d3eSLandon J. Fuller #define	BHND_NVRAM_VAL_ASSERT_EMPTY(_value)			\
9677cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(						\
9777cb4d3eSLandon J. Fuller 	    value->data_storage == BHND_NVRAM_VAL_DATA_NONE &&	\
9877cb4d3eSLandon J. Fuller 	    value->data_len == 0 &&				\
9977cb4d3eSLandon J. Fuller 	    value->data.ptr == NULL,				\
10077cb4d3eSLandon J. Fuller 	    ("previously initialized value"))
10177cb4d3eSLandon J. Fuller 
1029be0790dSLandon J. Fuller /** Return true if BHND_NVRAM_VAL_BORROW_DATA or BHND_NVRAM_VAL_STATIC_DATA is
1039be0790dSLandon J. Fuller  *  set in @p _flags (e.g. we should attempt to directly reference external
1049be0790dSLandon J. Fuller  *  data */
1059be0790dSLandon J. Fuller #define	BHND_NVRAM_VAL_EXTREF_BORROWED_DATA(_flags)		\
1069be0790dSLandon J. Fuller 	(((_flags) & BHND_NVRAM_VAL_BORROW_DATA) ||		\
1079be0790dSLandon J. Fuller 	 ((_flags) & BHND_NVRAM_VAL_STATIC_DATA))
1089be0790dSLandon J. Fuller 
1099be0790dSLandon J. Fuller /** Flags permitted when performing val-based initialization via
1109be0790dSLandon J. Fuller  *  bhnd_nvram_val_convert_init() or bhnd_nvram_val_convert_new() */
1119be0790dSLandon J. Fuller #define	BHND_NVRAM_VALID_CONV_FLAGS	\
1129be0790dSLandon J. Fuller 	(BHND_NVRAM_VAL_FIXED |		\
1139be0790dSLandon J. Fuller 	 BHND_NVRAM_VAL_DYNAMIC |	\
1149be0790dSLandon J. Fuller 	 BHND_NVRAM_VAL_COPY_DATA)
1159be0790dSLandon J. Fuller 
1169be0790dSLandon J. Fuller /** Returns true if @p _val must be copied in bhnd_nvram_val_copy(), false
1179be0790dSLandon J. Fuller  *  if its reference count may be safely incremented */
1189be0790dSLandon J. Fuller #define	BHND_NVRAM_VAL_NEED_COPY(_val)				\
1199be0790dSLandon J. Fuller 	((_val)->val_storage == BHND_NVRAM_VAL_STORAGE_AUTO ||	\
1209be0790dSLandon J. Fuller 	 (_val)->data_storage == BHND_NVRAM_VAL_DATA_EXT_WEAK)
1219be0790dSLandon J. Fuller 
1229be0790dSLandon J. Fuller volatile u_int			 refs;		/**< reference count */
1239be0790dSLandon J. Fuller bhnd_nvram_val_storage		 val_storage;	/**< value structure storage */
1249be0790dSLandon J. Fuller const bhnd_nvram_val_fmt	*fmt;		/**< value format */
1259be0790dSLandon J. Fuller bhnd_nvram_val_data_storage	 data_storage;	/**< data storage */
1269be0790dSLandon J. Fuller bhnd_nvram_type			 data_type;	/**< data type */
1279be0790dSLandon J. Fuller size_t				 data_len;	/**< data size */
1289be0790dSLandon J. Fuller 
1296cffadf0SLandon J. Fuller /* Shared NULL value instance */
1306cffadf0SLandon J. Fuller bhnd_nvram_val bhnd_nvram_val_null = {
1316cffadf0SLandon J. Fuller 	.refs		= 1,
1326cffadf0SLandon J. Fuller 	.val_storage	= BHND_NVRAM_VAL_STORAGE_STATIC,
1336cffadf0SLandon J. Fuller 	.fmt		= &bhnd_nvram_val_null_fmt,
1346cffadf0SLandon J. Fuller 	.data_storage	= BHND_NVRAM_VAL_DATA_INLINE,
1356cffadf0SLandon J. Fuller 	.data_type	= BHND_NVRAM_TYPE_NULL,
1366cffadf0SLandon J. Fuller 	.data_len	= 0,
1376cffadf0SLandon J. Fuller };
1386cffadf0SLandon J. Fuller 
1399be0790dSLandon J. Fuller /**
1409be0790dSLandon J. Fuller  * Return the human-readable name of @p fmt.
1419be0790dSLandon J. Fuller  */
1429be0790dSLandon J. Fuller const char *
bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt * fmt)1439be0790dSLandon J. Fuller bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt *fmt)
1449be0790dSLandon J. Fuller {
1459be0790dSLandon J. Fuller 	return (fmt->name);
1469be0790dSLandon J. Fuller }
1479be0790dSLandon J. Fuller 
1489be0790dSLandon J. Fuller /**
1499be0790dSLandon J. Fuller  * Return the default format for values of @p type.
1509be0790dSLandon J. Fuller  */
1519be0790dSLandon J. Fuller const bhnd_nvram_val_fmt *
bhnd_nvram_val_default_fmt(bhnd_nvram_type type)1529be0790dSLandon J. Fuller bhnd_nvram_val_default_fmt(bhnd_nvram_type type)
1539be0790dSLandon J. Fuller {
1549be0790dSLandon J. Fuller 	switch (type) {
1559be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
1569be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint8_fmt);
1579be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
1589be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint16_fmt);
1599be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
1609be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint32_fmt);
1619be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
1629be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint64_fmt);
1639be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
1649be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int8_fmt);
1659be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
1669be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int16_fmt);
1679be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
1689be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int32_fmt);
1699be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
1709be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int64_fmt);
1719be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
1729be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_char_fmt);
1739be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
1749be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_string_fmt);
1756cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
1766cffadf0SLandon J. Fuller 		return (&bhnd_nvram_val_bool_fmt);
1776cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
1786cffadf0SLandon J. Fuller 		return (&bhnd_nvram_val_null_fmt);
1796cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
1806cffadf0SLandon J. Fuller 		return (&bhnd_nvram_val_data_fmt);
1819be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
1829be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint8_array_fmt);
1839be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
1849be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint16_array_fmt);
1859be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
1869be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint32_array_fmt);
1879be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
1889be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_uint64_array_fmt);
1899be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
1909be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int8_array_fmt);
1919be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
1929be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int16_array_fmt);
1939be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
1949be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int32_array_fmt);
1959be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
1969be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_int64_array_fmt);
1979be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
1989be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_char_array_fmt);
1999be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
2009be0790dSLandon J. Fuller 		return (&bhnd_nvram_val_string_array_fmt);
2016cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
2026cffadf0SLandon J. Fuller 		return (&bhnd_nvram_val_bool_array_fmt);
2039be0790dSLandon J. Fuller 	}
2049be0790dSLandon J. Fuller 
2059be0790dSLandon J. Fuller 	/* Quiesce gcc4.2 */
2069be0790dSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
2079be0790dSLandon J. Fuller }
2089be0790dSLandon J. Fuller 
2099be0790dSLandon J. Fuller /**
2109be0790dSLandon J. Fuller  * Determine whether @p fmt (or new format delegated to by @p fmt) is
2119be0790dSLandon J. Fuller  * capable of direct initialization from buffer @p inp.
2129be0790dSLandon J. Fuller  *
2139be0790dSLandon J. Fuller  * @param[in,out]	fmt	Indirect pointer to the NVRAM value format. If
2149be0790dSLandon J. Fuller  *				the format instance cannot handle the data type
2159be0790dSLandon J. Fuller  *				directly, it may delegate to a new format
2169be0790dSLandon J. Fuller  *				instance. On success, this parameter will be
2179be0790dSLandon J. Fuller  *				set to the format that should be used when
2189be0790dSLandon J. Fuller  *				performing initialization from @p inp.
2199be0790dSLandon J. Fuller  * @param		inp	Input data.
2209be0790dSLandon J. Fuller  * @param		ilen	Input data length.
2219be0790dSLandon J. Fuller  * @param		itype	Input data type.
2229be0790dSLandon J. Fuller  *
2239be0790dSLandon J. Fuller  * @retval 0		If initialization from @p inp is supported.
2249be0790dSLandon J. Fuller  * @retval EFTYPE	If initialization from @p inp is unsupported.
2259be0790dSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
2269be0790dSLandon J. Fuller  *			@p itype.
2279be0790dSLandon J. Fuller  */
2289be0790dSLandon J. Fuller static int
bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt ** fmt,const void * inp,size_t ilen,bhnd_nvram_type itype)2299be0790dSLandon J. Fuller bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
2309be0790dSLandon J. Fuller     size_t ilen, bhnd_nvram_type itype)
2319be0790dSLandon J. Fuller {
2329be0790dSLandon J. Fuller 	const bhnd_nvram_val_fmt	*ofmt, *nfmt;
2339be0790dSLandon J. Fuller 	int				 error;
2349be0790dSLandon J. Fuller 
2359be0790dSLandon J. Fuller 	nfmt = ofmt = *fmt;
2369be0790dSLandon J. Fuller 
2379be0790dSLandon J. Fuller 	/* Validate alignment */
2389be0790dSLandon J. Fuller 	if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
2399be0790dSLandon J. Fuller 		return (error);
2409be0790dSLandon J. Fuller 
2419be0790dSLandon J. Fuller 	/* If the format does not provide a filter function, it only supports
2429be0790dSLandon J. Fuller 	 * direct initialization from its native type */
2439be0790dSLandon J. Fuller 	if (ofmt->op_filter == NULL) {
2449be0790dSLandon J. Fuller 		if (itype == ofmt->native_type)
2459be0790dSLandon J. Fuller 			return (0);
2469be0790dSLandon J. Fuller 
2479be0790dSLandon J. Fuller 		return (EFTYPE);
2489be0790dSLandon J. Fuller 	}
2499be0790dSLandon J. Fuller 
2509be0790dSLandon J. Fuller 	/* Use the filter function to determine whether direct initialization
2519be0790dSLandon J. Fuller 	 * from itype is permitted */
2529be0790dSLandon J. Fuller 	error = ofmt->op_filter(&nfmt, inp, ilen, itype);
2539be0790dSLandon J. Fuller 	if (error)
2549be0790dSLandon J. Fuller 		return (error);
2559be0790dSLandon J. Fuller 
2569be0790dSLandon J. Fuller 	/* Retry filter with new format? */
2579be0790dSLandon J. Fuller 	if (ofmt != nfmt) {
2589be0790dSLandon J. Fuller 		error = bhnd_nvram_val_fmt_filter(&nfmt, inp, ilen, itype);
2599be0790dSLandon J. Fuller 		if (error)
2609be0790dSLandon J. Fuller 			return (error);
2619be0790dSLandon J. Fuller 
2629be0790dSLandon J. Fuller 		/* Success -- provide delegated format to caller */
2639be0790dSLandon J. Fuller 		*fmt = nfmt;
2649be0790dSLandon J. Fuller 	}
2659be0790dSLandon J. Fuller 
2669be0790dSLandon J. Fuller 	/* Value can be initialized with provided format and input type */
2679be0790dSLandon J. Fuller 	return (0);
2689be0790dSLandon J. Fuller }
2699be0790dSLandon J. Fuller 
27077cb4d3eSLandon J. Fuller /* Common initialization support for bhnd_nvram_val_init() and
27177cb4d3eSLandon J. Fuller  * bhnd_nvram_val_new() */
27277cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_init_common(bhnd_nvram_val * value,bhnd_nvram_val_storage val_storage,const bhnd_nvram_val_fmt * fmt,const void * inp,size_t ilen,bhnd_nvram_type itype,uint32_t flags)27358efe686SLandon J. Fuller bhnd_nvram_val_init_common(bhnd_nvram_val *value,
27458efe686SLandon J. Fuller     bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
27558efe686SLandon J. Fuller     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
27677cb4d3eSLandon J. Fuller {
27777cb4d3eSLandon J. Fuller 	void		*outp;
27877cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype;
27977cb4d3eSLandon J. Fuller 	size_t		 olen;
28077cb4d3eSLandon J. Fuller 	int		 error;
28177cb4d3eSLandon J. Fuller 
2829be0790dSLandon J. Fuller 	/* If the value format is unspecified, we use the default format
2839be0790dSLandon J. Fuller 	 * for the input data type */
2849be0790dSLandon J. Fuller 	if (fmt == NULL)
2859be0790dSLandon J. Fuller 		fmt = bhnd_nvram_val_default_fmt(itype);
2869be0790dSLandon J. Fuller 
28777cb4d3eSLandon J. Fuller 	/* Determine expected data type, and allow the format to delegate to
28877cb4d3eSLandon J. Fuller 	 * a new format instance */
2899be0790dSLandon J. Fuller 	if ((error = bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype))) {
2909be0790dSLandon J. Fuller 		/* Direct initialization from the provided input type is
2919be0790dSLandon J. Fuller 		 * not supported; alue must be initialized with the format's
2929be0790dSLandon J. Fuller 		 * native type */
29377cb4d3eSLandon J. Fuller 		otype = fmt->native_type;
29477cb4d3eSLandon J. Fuller 	} else {
2959be0790dSLandon J. Fuller 		/* Value can be initialized with provided input type */
29677cb4d3eSLandon J. Fuller 		otype = itype;
29777cb4d3eSLandon J. Fuller 	}
29877cb4d3eSLandon J. Fuller 
29977cb4d3eSLandon J. Fuller 	/* Initialize value instance */
30077cb4d3eSLandon J. Fuller 	*value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
30177cb4d3eSLandon J. Fuller 
30277cb4d3eSLandon J. Fuller 	/* If input data already in native format, init directly. */
30377cb4d3eSLandon J. Fuller 	if (otype == itype) {
30477cb4d3eSLandon J. Fuller 		error = bhnd_nvram_val_set(value, inp, ilen, itype, flags);
30577cb4d3eSLandon J. Fuller 		if (error)
30677cb4d3eSLandon J. Fuller 			return (error);
30777cb4d3eSLandon J. Fuller 
30877cb4d3eSLandon J. Fuller 		return (0);
30977cb4d3eSLandon J. Fuller 	}
31077cb4d3eSLandon J. Fuller 
31177cb4d3eSLandon J. Fuller 	/* Determine size when encoded in native format */
31277cb4d3eSLandon J. Fuller 	error = bhnd_nvram_value_coerce(inp, ilen, itype, NULL, &olen, otype);
31377cb4d3eSLandon J. Fuller 	if (error)
31477cb4d3eSLandon J. Fuller 		return (error);
31577cb4d3eSLandon J. Fuller 
31677cb4d3eSLandon J. Fuller 	/* Fetch reference to (or allocate) an appropriately sized buffer */
31777cb4d3eSLandon J. Fuller 	outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
31877cb4d3eSLandon J. Fuller 	if (outp == NULL)
31977cb4d3eSLandon J. Fuller 		return (ENOMEM);
32077cb4d3eSLandon J. Fuller 
32177cb4d3eSLandon J. Fuller 	/* Perform encode */
32277cb4d3eSLandon J. Fuller 	error = bhnd_nvram_value_coerce(inp, ilen, itype, outp, &olen, otype);
32377cb4d3eSLandon J. Fuller 	if (error)
32477cb4d3eSLandon J. Fuller 		return (error);
32577cb4d3eSLandon J. Fuller 
32677cb4d3eSLandon J. Fuller 	return (0);
32777cb4d3eSLandon J. Fuller }
32877cb4d3eSLandon J. Fuller 
32977cb4d3eSLandon J. Fuller /**
33077cb4d3eSLandon J. Fuller  * Initialize an externally allocated instance of @p value with @p fmt from the
33177cb4d3eSLandon J. Fuller  * given @p inp buffer of @p itype and @p ilen.
33277cb4d3eSLandon J. Fuller  *
33377cb4d3eSLandon J. Fuller  * On success, the caller owns a reference to @p value, and is responsible for
33477cb4d3eSLandon J. Fuller  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
33577cb4d3eSLandon J. Fuller  *
33677cb4d3eSLandon J. Fuller  * @param	value	The externally allocated value instance to be
33777cb4d3eSLandon J. Fuller  *			initialized.
33877cb4d3eSLandon J. Fuller  * @param	fmt	The value's format, or NULL to use the default format
33977cb4d3eSLandon J. Fuller  *			for @p itype.
34077cb4d3eSLandon J. Fuller  * @param	inp	Input buffer.
34177cb4d3eSLandon J. Fuller  * @param	ilen	Input buffer length.
34277cb4d3eSLandon J. Fuller  * @param	itype	Input buffer type.
34377cb4d3eSLandon J. Fuller  * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
34477cb4d3eSLandon J. Fuller  *
34577cb4d3eSLandon J. Fuller  * @retval 0		success
34677cb4d3eSLandon J. Fuller  * @retval ENOMEM	If allocation fails.
34777cb4d3eSLandon J. Fuller  * @retval EFTYPE	If @p fmt initialization from @p itype is unsupported.
34877cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
34977cb4d3eSLandon J. Fuller  *			@p itype.
35077cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
35177cb4d3eSLandon J. Fuller  *			@p fmt representation.
35277cb4d3eSLandon J. Fuller  */
35377cb4d3eSLandon J. Fuller int
bhnd_nvram_val_init(bhnd_nvram_val * value,const bhnd_nvram_val_fmt * fmt,const void * inp,size_t ilen,bhnd_nvram_type itype,uint32_t flags)35458efe686SLandon J. Fuller bhnd_nvram_val_init(bhnd_nvram_val *value, const bhnd_nvram_val_fmt *fmt,
35577cb4d3eSLandon J. Fuller     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
35677cb4d3eSLandon J. Fuller {
35777cb4d3eSLandon J. Fuller 	int error;
35877cb4d3eSLandon J. Fuller 
35977cb4d3eSLandon J. Fuller 	error = bhnd_nvram_val_init_common(value, BHND_NVRAM_VAL_STORAGE_AUTO,
36077cb4d3eSLandon J. Fuller 	    fmt, inp, ilen, itype, flags);
36177cb4d3eSLandon J. Fuller 	if (error)
36277cb4d3eSLandon J. Fuller 		bhnd_nvram_val_release(value);
36377cb4d3eSLandon J. Fuller 
36477cb4d3eSLandon J. Fuller 	return (error);
36577cb4d3eSLandon J. Fuller }
36677cb4d3eSLandon J. Fuller 
36777cb4d3eSLandon J. Fuller /**
36877cb4d3eSLandon J. Fuller  * Allocate a value instance with @p fmt, and attempt to initialize its internal
36977cb4d3eSLandon J. Fuller  * representation from the given @p inp buffer of @p itype and @p ilen.
37077cb4d3eSLandon J. Fuller  *
37177cb4d3eSLandon J. Fuller  * On success, the caller owns a reference to @p value, and is responsible for
37277cb4d3eSLandon J. Fuller  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
37377cb4d3eSLandon J. Fuller  *
37477cb4d3eSLandon J. Fuller  * @param[out]	value	On success, the allocated value instance.
37577cb4d3eSLandon J. Fuller  * @param	fmt	The value's format, or NULL to use the default format
37677cb4d3eSLandon J. Fuller  *			for @p itype.
37777cb4d3eSLandon J. Fuller  * @param	inp	Input buffer.
37877cb4d3eSLandon J. Fuller  * @param	ilen	Input buffer length.
37977cb4d3eSLandon J. Fuller  * @param	itype	Input buffer type.
38077cb4d3eSLandon J. Fuller  * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
38177cb4d3eSLandon J. Fuller  *
38277cb4d3eSLandon J. Fuller  * @retval 0		success
38377cb4d3eSLandon J. Fuller  * @retval ENOMEM	If allocation fails.
38477cb4d3eSLandon J. Fuller  * @retval EFTYPE	If @p fmt initialization from @p itype is unsupported.
38577cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
38677cb4d3eSLandon J. Fuller  *			@p itype.
38777cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
38877cb4d3eSLandon J. Fuller  *			@p fmt representation.
38977cb4d3eSLandon J. Fuller  */
39077cb4d3eSLandon J. Fuller int
bhnd_nvram_val_new(bhnd_nvram_val ** value,const bhnd_nvram_val_fmt * fmt,const void * inp,size_t ilen,bhnd_nvram_type itype,uint32_t flags)39158efe686SLandon J. Fuller bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
39277cb4d3eSLandon J. Fuller     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
39377cb4d3eSLandon J. Fuller {
39477cb4d3eSLandon J. Fuller 	int error;
39577cb4d3eSLandon J. Fuller 
39677cb4d3eSLandon J. Fuller 	/* Allocate new instance */
39777cb4d3eSLandon J. Fuller 	if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
39877cb4d3eSLandon J. Fuller 		return (ENOMEM);
39977cb4d3eSLandon J. Fuller 
40077cb4d3eSLandon J. Fuller 	/* Perform common initialization. */
40177cb4d3eSLandon J. Fuller 	error = bhnd_nvram_val_init_common(*value,
40277cb4d3eSLandon J. Fuller 	    BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, inp, ilen, itype, flags);
40377cb4d3eSLandon J. Fuller 	if (error) {
40477cb4d3eSLandon J. Fuller 		/* Will also free() the value allocation */
40577cb4d3eSLandon J. Fuller 		bhnd_nvram_val_release(*value);
40677cb4d3eSLandon J. Fuller 	}
40777cb4d3eSLandon J. Fuller 
40877cb4d3eSLandon J. Fuller 	return (error);
40977cb4d3eSLandon J. Fuller }
41077cb4d3eSLandon J. Fuller 
4119be0790dSLandon J. Fuller /* Common initialization support for bhnd_nvram_val_convert_init() and
4129be0790dSLandon J. Fuller  * bhnd_nvram_val_convert_new() */
4139be0790dSLandon J. Fuller 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)4149be0790dSLandon J. Fuller bhnd_nvram_val_convert_common(bhnd_nvram_val *value,
4159be0790dSLandon J. Fuller     bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
4169be0790dSLandon J. Fuller     bhnd_nvram_val *src, uint32_t flags)
4179be0790dSLandon J. Fuller {
4189be0790dSLandon J. Fuller 	const void	*inp;
4199be0790dSLandon J. Fuller 	void		*outp;
4209be0790dSLandon J. Fuller 	bhnd_nvram_type	 itype, otype;
4219be0790dSLandon J. Fuller 	size_t		 ilen, olen;
4229be0790dSLandon J. Fuller 	int		 error;
4239be0790dSLandon J. Fuller 
4249be0790dSLandon J. Fuller 	/* Determine whether direct initialization from the source value's
4259be0790dSLandon J. Fuller 	 * existing data type is supported by the new format */
4269be0790dSLandon J. Fuller 	inp = bhnd_nvram_val_bytes(src, &ilen, &itype);
4279be0790dSLandon J. Fuller 	if (bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype) == 0) {
4289be0790dSLandon J. Fuller 		/* Adjust value flags based on the source data storage */
4299be0790dSLandon J. Fuller 		switch (src->data_storage) {
4309be0790dSLandon J. Fuller 		case BHND_NVRAM_VAL_DATA_NONE:
4319be0790dSLandon J. Fuller 		case BHND_NVRAM_VAL_DATA_INLINE:
4329be0790dSLandon J. Fuller 		case BHND_NVRAM_VAL_DATA_EXT_WEAK:
4339be0790dSLandon J. Fuller 		case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
4349be0790dSLandon J. Fuller 			break;
4359be0790dSLandon J. Fuller 
4369be0790dSLandon J. Fuller 		case BHND_NVRAM_VAL_DATA_EXT_STATIC:
4379be0790dSLandon J. Fuller 			/* If the source data has static storage duration,
4389be0790dSLandon J. Fuller 			 * we should apply that transitively */
4399be0790dSLandon J. Fuller 			if (flags & BHND_NVRAM_VAL_BORROW_DATA)
4409be0790dSLandon J. Fuller 				flags |= BHND_NVRAM_VAL_STATIC_DATA;
4419be0790dSLandon J. Fuller 
4429be0790dSLandon J. Fuller 			break;
4439be0790dSLandon J. Fuller 		}
4449be0790dSLandon J. Fuller 
4459be0790dSLandon J. Fuller 		/* Delegate to standard initialization */
4469be0790dSLandon J. Fuller 		return (bhnd_nvram_val_init_common(value, val_storage, fmt, inp,
4479be0790dSLandon J. Fuller 		    ilen, itype, flags));
4489be0790dSLandon J. Fuller 	}
4499be0790dSLandon J. Fuller 
4509be0790dSLandon J. Fuller 	/* Value must be initialized with the format's native type */
4519be0790dSLandon J. Fuller 	otype = fmt->native_type;
4529be0790dSLandon J. Fuller 
4539be0790dSLandon J. Fuller 	/* Initialize value instance */
4549be0790dSLandon J. Fuller 	*value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
4559be0790dSLandon J. Fuller 
4569be0790dSLandon J. Fuller 	/* Determine size when encoded in native format */
4579be0790dSLandon J. Fuller 	if ((error = bhnd_nvram_val_encode(src, NULL, &olen, otype)))
4589be0790dSLandon J. Fuller 		return (error);
4599be0790dSLandon J. Fuller 
4609be0790dSLandon J. Fuller 	/* Fetch reference to (or allocate) an appropriately sized buffer */
4619be0790dSLandon J. Fuller 	outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
4629be0790dSLandon J. Fuller 	if (outp == NULL)
4639be0790dSLandon J. Fuller 		return (ENOMEM);
4649be0790dSLandon J. Fuller 
4659be0790dSLandon J. Fuller 	/* Perform encode */
4669be0790dSLandon J. Fuller 	if ((error = bhnd_nvram_val_encode(src, outp, &olen, otype)))
4679be0790dSLandon J. Fuller 		return (error);
4689be0790dSLandon J. Fuller 
4699be0790dSLandon J. Fuller 	return (0);
4709be0790dSLandon J. Fuller }
4719be0790dSLandon J. Fuller 
4729be0790dSLandon J. Fuller /**
4739be0790dSLandon J. Fuller  * Initialize an externally allocated instance of @p value with @p fmt, and
4749be0790dSLandon J. Fuller  * attempt to initialize its internal representation from the given @p src
4759be0790dSLandon J. Fuller  * value.
4769be0790dSLandon J. Fuller  *
4779be0790dSLandon J. Fuller  * On success, the caller owns a reference to @p value, and is responsible for
4789be0790dSLandon J. Fuller  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
4799be0790dSLandon J. Fuller  *
4809be0790dSLandon J. Fuller  * @param	value	The externally allocated value instance to be
4819be0790dSLandon J. Fuller  *			initialized.
4829be0790dSLandon J. Fuller  * @param	fmt	The value's format.
4839be0790dSLandon J. Fuller  * @param	src	Input value to be converted.
4849be0790dSLandon J. Fuller  * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
4859be0790dSLandon J. Fuller  *
4869be0790dSLandon J. Fuller  * @retval 0		success
4879be0790dSLandon J. Fuller  * @retval ENOMEM	If allocation fails.
4889be0790dSLandon J. Fuller  * @retval EFTYPE	If @p fmt initialization from @p src is unsupported.
4899be0790dSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
4909be0790dSLandon J. Fuller  *			@p itype.
4919be0790dSLandon J. Fuller  * @retval ERANGE	If value coercion of @p src would overflow
4929be0790dSLandon J. Fuller  *			(or underflow) the @p fmt representation.
4939be0790dSLandon J. Fuller  */
4949be0790dSLandon J. Fuller int
bhnd_nvram_val_convert_init(bhnd_nvram_val * value,const bhnd_nvram_val_fmt * fmt,bhnd_nvram_val * src,uint32_t flags)4959be0790dSLandon J. Fuller bhnd_nvram_val_convert_init(bhnd_nvram_val *value,
4969be0790dSLandon J. Fuller     const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
4979be0790dSLandon J. Fuller {
4989be0790dSLandon J. Fuller 	int error;
4999be0790dSLandon J. Fuller 
5009be0790dSLandon J. Fuller 	error = bhnd_nvram_val_convert_common(value,
5019be0790dSLandon J. Fuller 	    BHND_NVRAM_VAL_STORAGE_AUTO, fmt, src, flags);
5029be0790dSLandon J. Fuller 	if (error)
5039be0790dSLandon J. Fuller 		bhnd_nvram_val_release(value);
5049be0790dSLandon J. Fuller 
5059be0790dSLandon J. Fuller 	return (error);
5069be0790dSLandon J. Fuller }
5079be0790dSLandon J. Fuller 
5089be0790dSLandon J. Fuller /**
5099be0790dSLandon J. Fuller  * Allocate a value instance with @p fmt, and attempt to initialize its internal
5109be0790dSLandon J. Fuller  * representation from the given @p src value.
5119be0790dSLandon J. Fuller  *
5129be0790dSLandon J. Fuller  * On success, the caller owns a reference to @p value, and is responsible for
5139be0790dSLandon J. Fuller  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
5149be0790dSLandon J. Fuller  *
5159be0790dSLandon J. Fuller  * @param[out]	value	On success, the allocated value instance.
5169be0790dSLandon J. Fuller  * @param	fmt	The value's format.
5179be0790dSLandon J. Fuller  * @param	src	Input value to be converted.
5189be0790dSLandon J. Fuller  * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
5199be0790dSLandon J. Fuller  *
5209be0790dSLandon J. Fuller  * @retval 0		success
5219be0790dSLandon J. Fuller  * @retval ENOMEM	If allocation fails.
5229be0790dSLandon J. Fuller  * @retval EFTYPE	If @p fmt initialization from @p src is unsupported.
5239be0790dSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
5249be0790dSLandon J. Fuller  *			@p itype.
5259be0790dSLandon J. Fuller  * @retval ERANGE	If value coercion of @p src would overflow
5269be0790dSLandon J. Fuller  *			(or underflow) the @p fmt representation.
5279be0790dSLandon J. Fuller  */
5289be0790dSLandon J. Fuller int
bhnd_nvram_val_convert_new(bhnd_nvram_val ** value,const bhnd_nvram_val_fmt * fmt,bhnd_nvram_val * src,uint32_t flags)5299be0790dSLandon J. Fuller bhnd_nvram_val_convert_new(bhnd_nvram_val **value,
5309be0790dSLandon J. Fuller     const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
5319be0790dSLandon J. Fuller {
5329be0790dSLandon J. Fuller 	int error;
5339be0790dSLandon J. Fuller 
5349be0790dSLandon J. Fuller 	/* Allocate new instance */
5359be0790dSLandon J. Fuller 	if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
5369be0790dSLandon J. Fuller 		return (ENOMEM);
5379be0790dSLandon J. Fuller 
5389be0790dSLandon J. Fuller 	/* Perform common initialization. */
5399be0790dSLandon J. Fuller 	error = bhnd_nvram_val_convert_common(*value,
5409be0790dSLandon J. Fuller 	    BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, src, flags);
5419be0790dSLandon J. Fuller 	if (error) {
5429be0790dSLandon J. Fuller 		/* Will also free() the value allocation */
5439be0790dSLandon J. Fuller 		bhnd_nvram_val_release(*value);
5449be0790dSLandon J. Fuller 	}
5459be0790dSLandon J. Fuller 
5469be0790dSLandon J. Fuller 	return (error);
5479be0790dSLandon J. Fuller }
5489be0790dSLandon J. Fuller 
54977cb4d3eSLandon J. Fuller /**
55077cb4d3eSLandon J. Fuller  * Copy or retain a reference to @p value.
55177cb4d3eSLandon J. Fuller  *
55277cb4d3eSLandon J. Fuller  * On success, the caller is responsible for freeing the result via
55377cb4d3eSLandon J. Fuller  * bhnd_nvram_val_release().
55477cb4d3eSLandon J. Fuller  *
55577cb4d3eSLandon J. Fuller  * @param	value	The value to be copied (or retained).
55677cb4d3eSLandon J. Fuller  *
55758efe686SLandon J. Fuller  * @retval bhnd_nvram_val	if @p value was successfully copied or retained.
55877cb4d3eSLandon J. Fuller  * @retval NULL			if allocation failed.
55977cb4d3eSLandon J. Fuller  */
56058efe686SLandon J. Fuller bhnd_nvram_val *
bhnd_nvram_val_copy(bhnd_nvram_val * value)56158efe686SLandon J. Fuller bhnd_nvram_val_copy(bhnd_nvram_val *value)
56277cb4d3eSLandon J. Fuller {
56358efe686SLandon J. Fuller 	bhnd_nvram_val		*result;
56477cb4d3eSLandon J. Fuller 	const void		*bytes;
56577cb4d3eSLandon J. Fuller 	bhnd_nvram_type		 type;
56677cb4d3eSLandon J. Fuller 	size_t			 len;
56777cb4d3eSLandon J. Fuller 	uint32_t		 flags;
56877cb4d3eSLandon J. Fuller 	int			 error;
56977cb4d3eSLandon J. Fuller 
5709be0790dSLandon J. Fuller 	switch (value->val_storage) {
5719be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_STORAGE_STATIC:
5729be0790dSLandon J. Fuller 		/* If static, can return as-is */
5739be0790dSLandon J. Fuller 		return (value);
5749be0790dSLandon J. Fuller 
5759be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_STORAGE_DYNAMIC:
5769be0790dSLandon J. Fuller 		if (!BHND_NVRAM_VAL_NEED_COPY(value)) {
57777cb4d3eSLandon J. Fuller 			refcount_acquire(&value->refs);
57877cb4d3eSLandon J. Fuller 			return (value);
57977cb4d3eSLandon J. Fuller 		}
58077cb4d3eSLandon J. Fuller 
5819be0790dSLandon J. Fuller 		/* Perform copy below */
5829be0790dSLandon J. Fuller 		break;
5839be0790dSLandon J. Fuller 
5849be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_STORAGE_AUTO:
58577cb4d3eSLandon J. Fuller 		BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
58677cb4d3eSLandon J. Fuller 		    "active refcount (%u)", value->refs));
58777cb4d3eSLandon J. Fuller 
5889be0790dSLandon J. Fuller 		/* Perform copy below */
5899be0790dSLandon J. Fuller 		break;
5909be0790dSLandon J. Fuller 	}
5919be0790dSLandon J. Fuller 
59277cb4d3eSLandon J. Fuller 	/* Compute the new value's flags based on the source value */
59377cb4d3eSLandon J. Fuller 	switch (value->data_storage) {
59477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_NONE:
59577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_INLINE:
59677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_WEAK:
59777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
59877cb4d3eSLandon J. Fuller 		/* Copy the source data and permit additional allocation if the
59977cb4d3eSLandon J. Fuller 		 * value cannot be represented inline */
60077cb4d3eSLandon J. Fuller 		flags = BHND_NVRAM_VAL_COPY_DATA|BHND_NVRAM_VAL_DYNAMIC;
60177cb4d3eSLandon J. Fuller 		break;
60277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_STATIC:
60377cb4d3eSLandon J. Fuller 		flags = BHND_NVRAM_VAL_STATIC_DATA;
60477cb4d3eSLandon J. Fuller 		break;
60577cb4d3eSLandon J. Fuller 	default:
60677cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("invalid storage type: %d", value->data_storage);
60777cb4d3eSLandon J. Fuller 	}
60877cb4d3eSLandon J. Fuller 
60977cb4d3eSLandon J. Fuller 	/* Allocate new value copy */
61077cb4d3eSLandon J. Fuller 	bytes = bhnd_nvram_val_bytes(value, &len, &type);
61177cb4d3eSLandon J. Fuller 	error = bhnd_nvram_val_new(&result, value->fmt, bytes, len, type,
61277cb4d3eSLandon J. Fuller 	    flags);
61377cb4d3eSLandon J. Fuller 	if (error) {
61477cb4d3eSLandon J. Fuller 		BHND_NV_LOG("copy failed: %d", error);
61577cb4d3eSLandon J. Fuller 		return (NULL);
61677cb4d3eSLandon J. Fuller 	}
61777cb4d3eSLandon J. Fuller 
61877cb4d3eSLandon J. Fuller 	return (result);
61977cb4d3eSLandon J. Fuller }
62077cb4d3eSLandon J. Fuller 
62177cb4d3eSLandon J. Fuller /**
62277cb4d3eSLandon J. Fuller  * Release a reference to @p value.
62377cb4d3eSLandon J. Fuller  *
62477cb4d3eSLandon J. Fuller  * If this is the last reference, all associated resources will be freed.
62577cb4d3eSLandon J. Fuller  *
62677cb4d3eSLandon J. Fuller  * @param	value	The value to be released.
62777cb4d3eSLandon J. Fuller  */
62877cb4d3eSLandon J. Fuller void
bhnd_nvram_val_release(bhnd_nvram_val * value)62958efe686SLandon J. Fuller bhnd_nvram_val_release(bhnd_nvram_val *value)
63077cb4d3eSLandon J. Fuller {
63177cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
63277cb4d3eSLandon J. Fuller 
6339be0790dSLandon J. Fuller 	/* Skip if value is static */
6349be0790dSLandon J. Fuller 	if (value->val_storage == BHND_NVRAM_VAL_STORAGE_STATIC)
6359be0790dSLandon J. Fuller 		return;
6369be0790dSLandon J. Fuller 
63777cb4d3eSLandon J. Fuller 	/* Drop reference */
63877cb4d3eSLandon J. Fuller 	if (!refcount_release(&value->refs))
63977cb4d3eSLandon J. Fuller 		return;
64077cb4d3eSLandon J. Fuller 
64177cb4d3eSLandon J. Fuller 	/* Free allocated external representation data */
6429be0790dSLandon J. Fuller 	switch (value->data_storage) {
6439be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
64477cb4d3eSLandon J. Fuller 		bhnd_nv_free(__DECONST(void *, value->data.ptr));
6459be0790dSLandon J. Fuller 		break;
6469be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_NONE:
6479be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_INLINE:
6489be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_WEAK:
6499be0790dSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_STATIC:
6509be0790dSLandon J. Fuller 		/* Nothing to free */
6519be0790dSLandon J. Fuller 		break;
6529be0790dSLandon J. Fuller 	}
65377cb4d3eSLandon J. Fuller 
65477cb4d3eSLandon J. Fuller 	/* Free instance if dynamically allocated */
65577cb4d3eSLandon J. Fuller 	if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
65677cb4d3eSLandon J. Fuller 		bhnd_nv_free(value);
65777cb4d3eSLandon J. Fuller }
65877cb4d3eSLandon J. Fuller 
65977cb4d3eSLandon J. Fuller /**
6606cffadf0SLandon J. Fuller  * Standard BHND_NVRAM_TYPE_NULL encoding implementation.
6616cffadf0SLandon J. Fuller  */
6626cffadf0SLandon J. Fuller static int
bhnd_nvram_val_encode_null(const void * inp,size_t ilen,bhnd_nvram_type itype,void * outp,size_t * olen,bhnd_nvram_type otype)6636cffadf0SLandon J. Fuller bhnd_nvram_val_encode_null(const void *inp, size_t ilen, bhnd_nvram_type itype,
6646cffadf0SLandon J. Fuller     void *outp, size_t *olen, bhnd_nvram_type otype)
6656cffadf0SLandon J. Fuller {
6666cffadf0SLandon J. Fuller 	size_t	limit, nbytes;
6676cffadf0SLandon J. Fuller 
6686cffadf0SLandon J. Fuller 	BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_NULL,
6696cffadf0SLandon J. Fuller 	    ("unsupported type: %d", itype));
6706cffadf0SLandon J. Fuller 
6716cffadf0SLandon J. Fuller 	/* Determine output byte limit */
6726cffadf0SLandon J. Fuller 	if (outp != NULL)
6736cffadf0SLandon J. Fuller 		limit = *olen;
6746cffadf0SLandon J. Fuller 	else
6756cffadf0SLandon J. Fuller 		limit = 0;
6766cffadf0SLandon J. Fuller 
6776cffadf0SLandon J. Fuller 	nbytes = 0;
6786cffadf0SLandon J. Fuller 
6796cffadf0SLandon J. Fuller 	/* Write to output */
6806cffadf0SLandon J. Fuller 	switch (otype) {
6816cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
6826cffadf0SLandon J. Fuller 		/* Can be directly encoded as a zero-length NULL value */
6836cffadf0SLandon J. Fuller 		nbytes = 0;
6846cffadf0SLandon J. Fuller 		break;
6856cffadf0SLandon J. Fuller 	default:
6866cffadf0SLandon J. Fuller 		/* Not representable */
6876cffadf0SLandon J. Fuller 		return (EFTYPE);
6886cffadf0SLandon J. Fuller 	}
6896cffadf0SLandon J. Fuller 
6906cffadf0SLandon J. Fuller 	/* Provide required length */
6916cffadf0SLandon J. Fuller 	*olen = nbytes;
6926cffadf0SLandon J. Fuller 	if (limit < *olen) {
6936cffadf0SLandon J. Fuller 		if (outp == NULL)
6946cffadf0SLandon J. Fuller 			return (0);
6956cffadf0SLandon J. Fuller 
6966cffadf0SLandon J. Fuller 		return (ENOMEM);
6976cffadf0SLandon J. Fuller 	}
6986cffadf0SLandon J. Fuller 
6996cffadf0SLandon J. Fuller 	return (0);
7006cffadf0SLandon J. Fuller }
7016cffadf0SLandon J. Fuller 
7026cffadf0SLandon J. Fuller /**
7036cffadf0SLandon J. Fuller  * Standard BHND_NVRAM_TYPE_BOOL encoding implementation.
7046cffadf0SLandon J. Fuller  */
7056cffadf0SLandon J. Fuller static int
bhnd_nvram_val_encode_bool(const void * inp,size_t ilen,bhnd_nvram_type itype,void * outp,size_t * olen,bhnd_nvram_type otype)7066cffadf0SLandon J. Fuller bhnd_nvram_val_encode_bool(const void *inp, size_t ilen, bhnd_nvram_type itype,
7076cffadf0SLandon J. Fuller     void *outp, size_t *olen, bhnd_nvram_type otype)
7086cffadf0SLandon J. Fuller {
7096cffadf0SLandon J. Fuller 	bhnd_nvram_bool_t	bval;
7106cffadf0SLandon J. Fuller 	size_t			limit, nbytes, nelem;
7116cffadf0SLandon J. Fuller 	int			error;
7126cffadf0SLandon J. Fuller 
7136cffadf0SLandon J. Fuller 	BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_BOOL,
7146cffadf0SLandon J. Fuller 	    ("unsupported type: %d", itype));
7156cffadf0SLandon J. Fuller 
7166cffadf0SLandon J. Fuller 	/* Determine output byte limit */
7176cffadf0SLandon J. Fuller 	if (outp != NULL)
7186cffadf0SLandon J. Fuller 		limit = *olen;
7196cffadf0SLandon J. Fuller 	else
7206cffadf0SLandon J. Fuller 		limit = 0;
7216cffadf0SLandon J. Fuller 
7226cffadf0SLandon J. Fuller 	/* Must be exactly one element in input */
7236cffadf0SLandon J. Fuller 	if ((error = bhnd_nvram_value_nelem(inp, ilen, itype, &nelem)))
7246cffadf0SLandon J. Fuller 		return (error);
7256cffadf0SLandon J. Fuller 
7266cffadf0SLandon J. Fuller 	if (nelem != 1)
7276cffadf0SLandon J. Fuller 		return (EFTYPE);
7286cffadf0SLandon J. Fuller 
7296cffadf0SLandon J. Fuller 	/* Fetch (and normalize) boolean value */
7306cffadf0SLandon J. Fuller 	bval = (*(const bhnd_nvram_bool_t *)inp != 0) ? true : false;
7316cffadf0SLandon J. Fuller 
7326cffadf0SLandon J. Fuller 	/* Write to output */
7336cffadf0SLandon J. Fuller 	switch (otype) {
7346cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
7356cffadf0SLandon J. Fuller 		/* False can be directly encoded as a zero-length NULL value */
7366cffadf0SLandon J. Fuller 		if (bval != false)
7376cffadf0SLandon J. Fuller 			return (EFTYPE);
7386cffadf0SLandon J. Fuller 
7396cffadf0SLandon J. Fuller 		nbytes = 0;
7406cffadf0SLandon J. Fuller 		break;
7416cffadf0SLandon J. Fuller 
7426cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
7436cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY: {
7446cffadf0SLandon J. Fuller 		/* Can encode as "true" or "false" */
7456cffadf0SLandon J. Fuller 		const char *str = bval ? "true" : "false";
7466cffadf0SLandon J. Fuller 
7476cffadf0SLandon J. Fuller 		nbytes = strlen(str) + 1;
7486cffadf0SLandon J. Fuller 		if (limit > nbytes)
7496cffadf0SLandon J. Fuller 			strcpy(outp, str);
7506cffadf0SLandon J. Fuller 
7516cffadf0SLandon J. Fuller 		break;
7526cffadf0SLandon J. Fuller 	}
7536cffadf0SLandon J. Fuller 
7546cffadf0SLandon J. Fuller 	default:
7556cffadf0SLandon J. Fuller 		/* If output type is an integer, we can delegate to standard
7566cffadf0SLandon J. Fuller 		 * integer encoding to encode as zero or one. */
7576cffadf0SLandon J. Fuller 		if (bhnd_nvram_is_int_type(otype)) {
7586cffadf0SLandon J. Fuller 			uint8_t	ival = bval ? 1 : 0;
7596cffadf0SLandon J. Fuller 
7606cffadf0SLandon J. Fuller 			return (bhnd_nvram_val_encode_int(&ival, sizeof(ival),
7616cffadf0SLandon J. Fuller 			    BHND_NVRAM_TYPE_UINT8, outp, olen, otype));
7626cffadf0SLandon J. Fuller 		}
7636cffadf0SLandon J. Fuller 
7646cffadf0SLandon J. Fuller 		/* Otherwise not representable */
7656cffadf0SLandon J. Fuller 		return (EFTYPE);
7666cffadf0SLandon J. Fuller 	}
7676cffadf0SLandon J. Fuller 
7686cffadf0SLandon J. Fuller 	/* Provide required length */
7696cffadf0SLandon J. Fuller 	*olen = nbytes;
7706cffadf0SLandon J. Fuller 	if (limit < *olen) {
7716cffadf0SLandon J. Fuller 		if (outp == NULL)
7726cffadf0SLandon J. Fuller 			return (0);
7736cffadf0SLandon J. Fuller 
7746cffadf0SLandon J. Fuller 		return (ENOMEM);
7756cffadf0SLandon J. Fuller 	}
7766cffadf0SLandon J. Fuller 
7776cffadf0SLandon J. Fuller 	return (0);
7786cffadf0SLandon J. Fuller }
7796cffadf0SLandon J. Fuller 
7806cffadf0SLandon J. Fuller /**
7816cffadf0SLandon J. Fuller  * Standard BHND_NVRAM_TYPE_DATA encoding implementation.
7826cffadf0SLandon J. Fuller  */
7836cffadf0SLandon J. Fuller static int
bhnd_nvram_val_encode_data(const void * inp,size_t ilen,bhnd_nvram_type itype,void * outp,size_t * olen,bhnd_nvram_type otype)7846cffadf0SLandon J. Fuller bhnd_nvram_val_encode_data(const void *inp, size_t ilen, bhnd_nvram_type itype,
7856cffadf0SLandon J. Fuller     void *outp, size_t *olen, bhnd_nvram_type otype)
7866cffadf0SLandon J. Fuller {
7876cffadf0SLandon J. Fuller 	BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_DATA,
7886cffadf0SLandon J. Fuller 	    ("unsupported type: %d", itype));
7896cffadf0SLandon J. Fuller 
7906cffadf0SLandon J. Fuller 	/* Write to output */
7916cffadf0SLandon J. Fuller 	switch (otype) {
7926cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
7936cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
7946cffadf0SLandon J. Fuller 		/* If encoding as a string, produce an EFI-style hexadecimal
7956cffadf0SLandon J. Fuller 		 * byte array (HF1F...) by interpreting the octet string
7966cffadf0SLandon J. Fuller 		 * as an array of uint8 values */
7976cffadf0SLandon J. Fuller 		return (bhnd_nvram_value_printf("H%[]02hhX", inp, ilen,
7986cffadf0SLandon J. Fuller 		    BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, ""));
7996cffadf0SLandon J. Fuller 
8006cffadf0SLandon J. Fuller 	default:
8016cffadf0SLandon J. Fuller 		/* Fall back on direct interpretation as an array of 8-bit
8026cffadf0SLandon J. Fuller 		 * integers array */
8036cffadf0SLandon J. Fuller 		return (bhnd_nvram_value_coerce(inp, ilen,
8046cffadf0SLandon J. Fuller 		    BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, otype));
8056cffadf0SLandon J. Fuller 	}
8066cffadf0SLandon J. Fuller }
8076cffadf0SLandon J. Fuller 
8086cffadf0SLandon J. Fuller /**
80977cb4d3eSLandon J. Fuller  * Standard string/char array/char encoding implementation.
81077cb4d3eSLandon J. Fuller  *
81177cb4d3eSLandon J. Fuller  * Input type must be one of:
81277cb4d3eSLandon J. Fuller  * - BHND_NVRAM_TYPE_STRING
81377cb4d3eSLandon J. Fuller  * - BHND_NVRAM_TYPE_CHAR
81477cb4d3eSLandon J. Fuller  * - BHND_NVRAM_TYPE_CHAR_ARRAY
81577cb4d3eSLandon J. Fuller  */
81677cb4d3eSLandon J. Fuller 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)8179be0790dSLandon J. Fuller bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
8189be0790dSLandon J. Fuller     bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype)
81977cb4d3eSLandon J. Fuller {
82077cb4d3eSLandon J. Fuller 	const char	*cstr;
82177cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype_base;
82277cb4d3eSLandon J. Fuller 	size_t		 cstr_size, cstr_len;
82377cb4d3eSLandon J. Fuller 	size_t		 limit, nbytes;
82477cb4d3eSLandon J. Fuller 
82577cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(
82677cb4d3eSLandon J. Fuller 	    itype == BHND_NVRAM_TYPE_STRING ||
82777cb4d3eSLandon J. Fuller 	    itype == BHND_NVRAM_TYPE_CHAR ||
82877cb4d3eSLandon J. Fuller 	    itype == BHND_NVRAM_TYPE_CHAR_ARRAY,
82977cb4d3eSLandon J. Fuller 	    ("unsupported type: %d", itype));
83077cb4d3eSLandon J. Fuller 
83177cb4d3eSLandon J. Fuller 	cstr = inp;
83277cb4d3eSLandon J. Fuller 	cstr_size = ilen;
83377cb4d3eSLandon J. Fuller 	nbytes = 0;
83477cb4d3eSLandon J. Fuller 	otype_base = bhnd_nvram_base_type(otype);
83577cb4d3eSLandon J. Fuller 
83677cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
83777cb4d3eSLandon J. Fuller 	if (outp != NULL)
83877cb4d3eSLandon J. Fuller 		limit = *olen;
83977cb4d3eSLandon J. Fuller 	else
84077cb4d3eSLandon J. Fuller 		limit = 0;
84177cb4d3eSLandon J. Fuller 
84277cb4d3eSLandon J. Fuller 	/* Determine string length, minus trailing NUL (if any) */
84377cb4d3eSLandon J. Fuller 	cstr_len = strnlen(cstr, cstr_size);
84477cb4d3eSLandon J. Fuller 
8459be0790dSLandon J. Fuller 	/* Parse the string data and write to output */
84677cb4d3eSLandon J. Fuller 	switch (otype) {
8476cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
8486cffadf0SLandon J. Fuller 		/* Only an empty string may be represented as a NULL value */
8496cffadf0SLandon J. Fuller 		if (cstr_len != 0)
8506cffadf0SLandon J. Fuller 			return (EFTYPE);
8516cffadf0SLandon J. Fuller 
8526cffadf0SLandon J. Fuller 		*olen = 0;
8536cffadf0SLandon J. Fuller 		return (0);
8546cffadf0SLandon J. Fuller 
85577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
85677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
85777cb4d3eSLandon J. Fuller 		/* String must contain exactly 1 non-terminating-NUL character
85877cb4d3eSLandon J. Fuller 		 * to be represented as a single char */
85977cb4d3eSLandon J. Fuller 		if (!bhnd_nvram_is_array_type(otype)) {
86077cb4d3eSLandon J. Fuller 			if (cstr_len != 1)
86177cb4d3eSLandon J. Fuller 				return (EFTYPE);
86277cb4d3eSLandon J. Fuller 		}
86377cb4d3eSLandon J. Fuller 
86477cb4d3eSLandon J. Fuller 		/* Copy out the characters directly (excluding trailing NUL) */
86577cb4d3eSLandon J. Fuller 		for (size_t i = 0; i < cstr_len; i++) {
86677cb4d3eSLandon J. Fuller 			if (limit > nbytes)
86777cb4d3eSLandon J. Fuller 				*((uint8_t *)outp + nbytes) = cstr[i];
86877cb4d3eSLandon J. Fuller 			nbytes++;
86977cb4d3eSLandon J. Fuller 		}
87077cb4d3eSLandon J. Fuller 
87177cb4d3eSLandon J. Fuller 		/* Provide required length */
87277cb4d3eSLandon J. Fuller 		*olen = nbytes;
87377cb4d3eSLandon J. Fuller 		if (limit < *olen && outp != NULL)
87477cb4d3eSLandon J. Fuller 			return (ENOMEM);
87577cb4d3eSLandon J. Fuller 
87677cb4d3eSLandon J. Fuller 		return (0);
87777cb4d3eSLandon J. Fuller 
8786cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
8796cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY: {
8806cffadf0SLandon J. Fuller 		const char		*p;
8816cffadf0SLandon J. Fuller 		size_t			 plen;
8826cffadf0SLandon J. Fuller 		bhnd_nvram_bool_t	 bval;
8836cffadf0SLandon J. Fuller 
8846cffadf0SLandon J. Fuller 		/* Trim leading/trailing whitespace */
8856cffadf0SLandon J. Fuller 		p = cstr;
8866cffadf0SLandon J. Fuller 		plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
8876cffadf0SLandon J. Fuller 
8886cffadf0SLandon J. Fuller 		/* Parse string representation */
8896cffadf0SLandon J. Fuller 		if (strncasecmp(p, "true", plen) == 0 ||
8906cffadf0SLandon J. Fuller 		    strncasecmp(p, "yes", plen) == 0 ||
8916cffadf0SLandon J. Fuller 		    strncmp(p, "1", plen) == 0)
8926cffadf0SLandon J. Fuller 		{
8936cffadf0SLandon J. Fuller 			bval = true;
8946cffadf0SLandon J. Fuller 		} else if (strncasecmp(p, "false", plen) == 0 ||
8956cffadf0SLandon J. Fuller 		    strncasecmp(p, "no", plen) == 0 ||
8966cffadf0SLandon J. Fuller 		    strncmp(p, "0", plen) == 0)
8976cffadf0SLandon J. Fuller 		{
8986cffadf0SLandon J. Fuller 			bval = false;
8996cffadf0SLandon J. Fuller 		} else {
9006cffadf0SLandon J. Fuller 			/* Not a recognized boolean string */
9016cffadf0SLandon J. Fuller 			return (EFTYPE);
9026cffadf0SLandon J. Fuller 		}
9036cffadf0SLandon J. Fuller 
9046cffadf0SLandon J. Fuller 		/* Write to output */
9056cffadf0SLandon J. Fuller 		nbytes = sizeof(bhnd_nvram_bool_t);
9066cffadf0SLandon J. Fuller 		if (limit >= nbytes)
9076cffadf0SLandon J. Fuller 			*((bhnd_nvram_bool_t *)outp) = bval;
9086cffadf0SLandon J. Fuller 
9096cffadf0SLandon J. Fuller 		/* Provide required length */
9106cffadf0SLandon J. Fuller 		*olen = nbytes;
9116cffadf0SLandon J. Fuller 		if (limit < *olen && outp != NULL)
9126cffadf0SLandon J. Fuller 			return (ENOMEM);
9136cffadf0SLandon J. Fuller 
9146cffadf0SLandon J. Fuller 		return (0);
9156cffadf0SLandon J. Fuller 	}
9166cffadf0SLandon J. Fuller 
9176cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA: {
9186cffadf0SLandon J. Fuller 		const char	*p;
9196cffadf0SLandon J. Fuller 		size_t		 plen, parsed_len;
9206cffadf0SLandon J. Fuller 		int		 error;
9216cffadf0SLandon J. Fuller 
9226cffadf0SLandon J. Fuller 		/* Trim leading/trailing whitespace */
9236cffadf0SLandon J. Fuller 		p = cstr;
9246cffadf0SLandon J. Fuller 		plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
9256cffadf0SLandon J. Fuller 
9266cffadf0SLandon J. Fuller 		/* Check for EFI-style hexadecimal byte array string format.
9276cffadf0SLandon J. Fuller 		 * Must have a 'H' prefix  */
9286cffadf0SLandon J. Fuller 		if (plen < 1 || bhnd_nv_toupper(*p) != 'H')
9296cffadf0SLandon J. Fuller 			return (EFTYPE);
9306cffadf0SLandon J. Fuller 
9316cffadf0SLandon J. Fuller 		/* Skip leading 'H' */
9326cffadf0SLandon J. Fuller 		p++;
9336cffadf0SLandon J. Fuller 		plen--;
9346cffadf0SLandon J. Fuller 
9356cffadf0SLandon J. Fuller 		/* Parse the input string's two-char octets until the end
9366cffadf0SLandon J. Fuller 		 * of input is reached. The last octet may contain only
9376cffadf0SLandon J. Fuller 		 * one char */
9386cffadf0SLandon J. Fuller 		while (plen > 0) {
9396cffadf0SLandon J. Fuller 			uint8_t	byte;
9406cffadf0SLandon J. Fuller 			size_t	byte_len = sizeof(byte);
9416cffadf0SLandon J. Fuller 
9426cffadf0SLandon J. Fuller 			/* Parse next two-character hex octet */
9436cffadf0SLandon J. Fuller 			error = bhnd_nvram_parse_int(p, bhnd_nv_ummin(plen, 2),
9446cffadf0SLandon J. Fuller 			    16, &parsed_len, &byte, &byte_len, otype_base);
9456cffadf0SLandon J. Fuller 			if (error) {
9466cffadf0SLandon J. Fuller 				BHND_NV_DEBUG("error parsing '%.*s' as "
9476cffadf0SLandon J. Fuller 				    "integer: %d\n", BHND_NV_PRINT_WIDTH(plen),
9486cffadf0SLandon J. Fuller 				     p, error);
9496cffadf0SLandon J. Fuller 
9506cffadf0SLandon J. Fuller 				return (error);
9516cffadf0SLandon J. Fuller 			}
9526cffadf0SLandon J. Fuller 
9536cffadf0SLandon J. Fuller 			/* Write to output */
9546cffadf0SLandon J. Fuller 			if (limit > nbytes)
9556cffadf0SLandon J. Fuller 				*((uint8_t *)outp + nbytes) = byte;
9566cffadf0SLandon J. Fuller 			nbytes++;
9576cffadf0SLandon J. Fuller 
9586cffadf0SLandon J. Fuller 			/* Advance input */
9596cffadf0SLandon J. Fuller 			p += parsed_len;
9606cffadf0SLandon J. Fuller 			plen -= parsed_len;
9616cffadf0SLandon J. Fuller 		}
9626cffadf0SLandon J. Fuller 
9636cffadf0SLandon J. Fuller 		/* Provide required length */
9646cffadf0SLandon J. Fuller 		*olen = nbytes;
9656cffadf0SLandon J. Fuller 		if (limit < *olen && outp != NULL)
9666cffadf0SLandon J. Fuller 			return (ENOMEM);
9676cffadf0SLandon J. Fuller 
9686cffadf0SLandon J. Fuller 		return (0);
9696cffadf0SLandon J. Fuller 	}
9706cffadf0SLandon J. Fuller 
97177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
97277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
97377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
97477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
97577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
97677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
97777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
97877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
97977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
98077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
98177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
98277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
98377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
98477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
98577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
98677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY: {
98777cb4d3eSLandon J. Fuller 		const char	*p;
98877cb4d3eSLandon J. Fuller 		size_t		 plen, parsed_len;
98977cb4d3eSLandon J. Fuller 		int		 error;
99077cb4d3eSLandon J. Fuller 
99177cb4d3eSLandon J. Fuller 		/* Trim leading/trailing whitespace */
99277cb4d3eSLandon J. Fuller 		p = cstr;
99377cb4d3eSLandon J. Fuller 		plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
99477cb4d3eSLandon J. Fuller 
99577cb4d3eSLandon J. Fuller 		/* Try to parse the integer value */
99677cb4d3eSLandon J. Fuller 		error = bhnd_nvram_parse_int(p, plen, 0, &parsed_len, outp,
99777cb4d3eSLandon J. Fuller 		    olen, otype_base);
99877cb4d3eSLandon J. Fuller 		if (error) {
99977cb4d3eSLandon J. Fuller 			BHND_NV_DEBUG("error parsing '%.*s' as integer: %d\n",
100077cb4d3eSLandon J. Fuller 			    BHND_NV_PRINT_WIDTH(plen), p, error);
100177cb4d3eSLandon J. Fuller 			return (error);
100277cb4d3eSLandon J. Fuller 		}
100377cb4d3eSLandon J. Fuller 
100477cb4d3eSLandon J. Fuller 		/* Do additional bytes remain unparsed? */
100577cb4d3eSLandon J. Fuller 		if (plen != parsed_len) {
100677cb4d3eSLandon J. Fuller 			BHND_NV_DEBUG("error parsing '%.*s' as a single "
100777cb4d3eSLandon J. Fuller 			    "integer value; trailing garbage '%.*s'\n",
100877cb4d3eSLandon J. Fuller 			    BHND_NV_PRINT_WIDTH(plen), p,
100977cb4d3eSLandon J. Fuller 			    BHND_NV_PRINT_WIDTH(plen-parsed_len), p+parsed_len);
101077cb4d3eSLandon J. Fuller 			return (EFTYPE);
101177cb4d3eSLandon J. Fuller 		}
101277cb4d3eSLandon J. Fuller 
101377cb4d3eSLandon J. Fuller 		return (0);
101477cb4d3eSLandon J. Fuller 	}
101577cb4d3eSLandon J. Fuller 
101677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
101777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
101877cb4d3eSLandon J. Fuller 		/* Copy out the string representation as-is */
101977cb4d3eSLandon J. Fuller 		*olen = cstr_size;
102077cb4d3eSLandon J. Fuller 
102177cb4d3eSLandon J. Fuller 		/* Need additional space for trailing NUL? */
102277cb4d3eSLandon J. Fuller 		if (cstr_len == cstr_size)
102377cb4d3eSLandon J. Fuller 			(*olen)++;
102477cb4d3eSLandon J. Fuller 
102577cb4d3eSLandon J. Fuller 		/* Skip output? */
102677cb4d3eSLandon J. Fuller 		if (outp == NULL)
102777cb4d3eSLandon J. Fuller 			return (0);
102877cb4d3eSLandon J. Fuller 
102977cb4d3eSLandon J. Fuller 		/* Verify required length */
103077cb4d3eSLandon J. Fuller 		if (limit < *olen)
103177cb4d3eSLandon J. Fuller 			return (ENOMEM);
103277cb4d3eSLandon J. Fuller 
103377cb4d3eSLandon J. Fuller 		/* Copy and NUL terminate */
103477cb4d3eSLandon J. Fuller 		strncpy(outp, cstr, cstr_len);
103577cb4d3eSLandon J. Fuller 		*((char *)outp + cstr_len) = '\0';
103677cb4d3eSLandon J. Fuller 
103777cb4d3eSLandon J. Fuller 		return (0);
103877cb4d3eSLandon J. Fuller 	}
103977cb4d3eSLandon J. Fuller 
104077cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("unknown type %s", bhnd_nvram_type_name(otype));
104177cb4d3eSLandon J. Fuller }
104277cb4d3eSLandon J. Fuller 
104377cb4d3eSLandon J. Fuller /**
104477cb4d3eSLandon J. Fuller  * Standard integer encoding implementation.
104577cb4d3eSLandon J. Fuller  */
104677cb4d3eSLandon J. Fuller 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)10479be0790dSLandon J. Fuller bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype,
10489be0790dSLandon J. Fuller     void *outp, size_t *olen, bhnd_nvram_type otype)
104977cb4d3eSLandon J. Fuller {
105077cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype_base;
105177cb4d3eSLandon J. Fuller 	size_t		 limit, nbytes;
105277cb4d3eSLandon J. Fuller 	bool		 itype_signed, otype_signed, otype_int;
105377cb4d3eSLandon J. Fuller 	union {
105477cb4d3eSLandon J. Fuller 		uint64_t	u64;
105577cb4d3eSLandon J. Fuller 		int64_t		i64;
105677cb4d3eSLandon J. Fuller 	} intv;
105777cb4d3eSLandon J. Fuller 
105877cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("non-integer type"));
105977cb4d3eSLandon J. Fuller 
106077cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
106177cb4d3eSLandon J. Fuller 	if (outp != NULL)
106277cb4d3eSLandon J. Fuller 		limit = *olen;
106377cb4d3eSLandon J. Fuller 	else
106477cb4d3eSLandon J. Fuller 		limit = 0;
106577cb4d3eSLandon J. Fuller 
106677cb4d3eSLandon J. Fuller 	/* Fetch output type info */
106777cb4d3eSLandon J. Fuller 	otype_base = bhnd_nvram_base_type(otype);
106877cb4d3eSLandon J. Fuller 	otype_int = bhnd_nvram_is_int_type(otype);
106977cb4d3eSLandon J. Fuller 	otype_signed = bhnd_nvram_is_signed_type(otype_base);
107077cb4d3eSLandon J. Fuller 
107177cb4d3eSLandon J. Fuller 	/*
107277cb4d3eSLandon J. Fuller 	 * Promote integer value to a common 64-bit representation.
107377cb4d3eSLandon J. Fuller 	 */
107477cb4d3eSLandon J. Fuller 	switch (itype) {
107577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
107677cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint8_t))
107777cb4d3eSLandon J. Fuller 			return (EFAULT);
107877cb4d3eSLandon J. Fuller 
107977cb4d3eSLandon J. Fuller 		itype_signed = false;
108077cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint8_t *)inp;
108177cb4d3eSLandon J. Fuller 		break;
108277cb4d3eSLandon J. Fuller 
108377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
108477cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint16_t))
108577cb4d3eSLandon J. Fuller 			return (EFAULT);
108677cb4d3eSLandon J. Fuller 
108777cb4d3eSLandon J. Fuller 		itype_signed = false;
108877cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint16_t *)inp;
108977cb4d3eSLandon J. Fuller 		break;
109077cb4d3eSLandon J. Fuller 
109177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
109277cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint32_t))
109377cb4d3eSLandon J. Fuller 			return (EFAULT);
109477cb4d3eSLandon J. Fuller 
109577cb4d3eSLandon J. Fuller 		itype_signed = false;
109677cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint32_t *)inp;
109777cb4d3eSLandon J. Fuller 		break;
109877cb4d3eSLandon J. Fuller 
109977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
110077cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint64_t))
110177cb4d3eSLandon J. Fuller 			return (EFAULT);
110277cb4d3eSLandon J. Fuller 
110377cb4d3eSLandon J. Fuller 		itype_signed = false;
110477cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint64_t *)inp;
110577cb4d3eSLandon J. Fuller 		break;
110677cb4d3eSLandon J. Fuller 
110777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
110877cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int8_t))
110977cb4d3eSLandon J. Fuller 			return (EFAULT);
111077cb4d3eSLandon J. Fuller 
111177cb4d3eSLandon J. Fuller 		itype_signed = true;
111277cb4d3eSLandon J. Fuller 		intv.i64 = *(const int8_t *)inp;
111377cb4d3eSLandon J. Fuller 		break;
111477cb4d3eSLandon J. Fuller 
111577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
111677cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int16_t))
111777cb4d3eSLandon J. Fuller 			return (EFAULT);
111877cb4d3eSLandon J. Fuller 
111977cb4d3eSLandon J. Fuller 		itype_signed = true;
112077cb4d3eSLandon J. Fuller 		intv.i64 = *(const int16_t *)inp;
112177cb4d3eSLandon J. Fuller 		break;
112277cb4d3eSLandon J. Fuller 
112377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
112477cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int32_t))
112577cb4d3eSLandon J. Fuller 			return (EFAULT);
112677cb4d3eSLandon J. Fuller 
112777cb4d3eSLandon J. Fuller 		itype_signed = true;
112877cb4d3eSLandon J. Fuller 		intv.i64 = *(const int32_t *)inp;
112977cb4d3eSLandon J. Fuller 		break;
113077cb4d3eSLandon J. Fuller 
113177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
113277cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int32_t))
113377cb4d3eSLandon J. Fuller 			return (EFAULT);
113477cb4d3eSLandon J. Fuller 
113577cb4d3eSLandon J. Fuller 		itype_signed = true;
113677cb4d3eSLandon J. Fuller 		intv.i64 = *(const int32_t *)inp;
113777cb4d3eSLandon J. Fuller 		break;
113877cb4d3eSLandon J. Fuller 
113977cb4d3eSLandon J. Fuller 	default:
114077cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("invalid type %d\n", itype);
114177cb4d3eSLandon J. Fuller 	}
114277cb4d3eSLandon J. Fuller 
114377cb4d3eSLandon J. Fuller 	/* Perform signed/unsigned conversion */
114477cb4d3eSLandon J. Fuller 	if (itype_signed && otype_int && !otype_signed) {
114577cb4d3eSLandon J. Fuller 		if (intv.i64 < 0) {
114677cb4d3eSLandon J. Fuller 			/* Can't represent negative value */
114777cb4d3eSLandon J. Fuller 			BHND_NV_LOG("cannot represent %" PRId64 " as %s\n",
114877cb4d3eSLandon J. Fuller 			    intv.i64, bhnd_nvram_type_name(otype));
114977cb4d3eSLandon J. Fuller 
115077cb4d3eSLandon J. Fuller 			return (ERANGE);
115177cb4d3eSLandon J. Fuller 		}
115277cb4d3eSLandon J. Fuller 
115377cb4d3eSLandon J. Fuller 		/* Convert to unsigned representation */
115477cb4d3eSLandon J. Fuller 		intv.u64 = intv.i64;
115577cb4d3eSLandon J. Fuller 
115677cb4d3eSLandon J. Fuller 	} else if (!itype_signed && otype_int && otype_signed) {
115777cb4d3eSLandon J. Fuller 		/* Handle unsigned -> signed coercions */
115877cb4d3eSLandon J. Fuller 		if (intv.u64 > INT64_MAX) {
115977cb4d3eSLandon J. Fuller 			/* Can't represent positive value */
116077cb4d3eSLandon J. Fuller 			BHND_NV_LOG("cannot represent %" PRIu64 " as %s\n",
116177cb4d3eSLandon J. Fuller 			    intv.u64, bhnd_nvram_type_name(otype));
116277cb4d3eSLandon J. Fuller 			return (ERANGE);
116377cb4d3eSLandon J. Fuller 		}
116477cb4d3eSLandon J. Fuller 
116577cb4d3eSLandon J. Fuller 		/* Convert to signed representation */
116677cb4d3eSLandon J. Fuller 		intv.i64 = intv.u64;
116777cb4d3eSLandon J. Fuller 	}
116877cb4d3eSLandon J. Fuller 
116977cb4d3eSLandon J. Fuller 	/* Write output */
117077cb4d3eSLandon J. Fuller 	switch (otype) {
11716cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
11726cffadf0SLandon J. Fuller 		/* Cannot encode an integer value as NULL */
11736cffadf0SLandon J. Fuller 		return (EFTYPE);
11746cffadf0SLandon J. Fuller 
11756cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL: {
11766cffadf0SLandon J. Fuller 		bhnd_nvram_bool_t bval;
11776cffadf0SLandon J. Fuller 
11786cffadf0SLandon J. Fuller 		if (intv.u64 == 0 || intv.u64 == 1) {
11796cffadf0SLandon J. Fuller 			bval = intv.u64;
11806cffadf0SLandon J. Fuller 		} else {
11816cffadf0SLandon J. Fuller 			/* Encoding as a bool would lose information */
11826cffadf0SLandon J. Fuller 			return (ERANGE);
11836cffadf0SLandon J. Fuller 		}
11846cffadf0SLandon J. Fuller 
11856cffadf0SLandon J. Fuller 		nbytes = sizeof(bhnd_nvram_bool_t);
11866cffadf0SLandon J. Fuller 		if (limit >= nbytes)
11876cffadf0SLandon J. Fuller 			*((bhnd_nvram_bool_t *)outp) = bval;
11886cffadf0SLandon J. Fuller 
11896cffadf0SLandon J. Fuller 		break;
11906cffadf0SLandon J. Fuller 	}
11916cffadf0SLandon J. Fuller 
119277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
119377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
11946cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
119577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
119677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
119777cb4d3eSLandon J. Fuller 		if (intv.u64 > UINT8_MAX)
119877cb4d3eSLandon J. Fuller 			return (ERANGE);
119977cb4d3eSLandon J. Fuller 
120077cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint8_t);
120177cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
120277cb4d3eSLandon J. Fuller 			*((uint8_t *)outp) = (uint8_t)intv.u64;
120377cb4d3eSLandon J. Fuller 		break;
120477cb4d3eSLandon J. Fuller 
120577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
120677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
120777cb4d3eSLandon J. Fuller 		if (intv.u64 > UINT16_MAX)
120877cb4d3eSLandon J. Fuller 			return (ERANGE);
120977cb4d3eSLandon J. Fuller 
121077cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint16_t);
121177cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
121277cb4d3eSLandon J. Fuller 			*((uint16_t *)outp) = (uint16_t)intv.u64;
121377cb4d3eSLandon J. Fuller 		break;
121477cb4d3eSLandon J. Fuller 
121577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
121677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
121777cb4d3eSLandon J. Fuller 		if (intv.u64 > UINT32_MAX)
121877cb4d3eSLandon J. Fuller 			return (ERANGE);
121977cb4d3eSLandon J. Fuller 
122077cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint32_t);
122177cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
122277cb4d3eSLandon J. Fuller 			*((uint32_t *)outp) = (uint32_t)intv.u64;
122377cb4d3eSLandon J. Fuller 		break;
122477cb4d3eSLandon J. Fuller 
122577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
122677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
122777cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint64_t);
122877cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
122977cb4d3eSLandon J. Fuller 			*((uint64_t *)outp) = intv.u64;
123077cb4d3eSLandon J. Fuller 		break;
123177cb4d3eSLandon J. Fuller 
123277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
123377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
123477cb4d3eSLandon J. Fuller 		if (intv.i64 < INT8_MIN || intv.i64 > INT8_MAX)
123577cb4d3eSLandon J. Fuller 			return (ERANGE);
123677cb4d3eSLandon J. Fuller 
123777cb4d3eSLandon J. Fuller 		nbytes = sizeof(int8_t);
123877cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
123977cb4d3eSLandon J. Fuller 			*((int8_t *)outp) = (int8_t)intv.i64;
124077cb4d3eSLandon J. Fuller 		break;
124177cb4d3eSLandon J. Fuller 
124277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
124377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
124477cb4d3eSLandon J. Fuller 		if (intv.i64 < INT16_MIN || intv.i64 > INT16_MAX)
124577cb4d3eSLandon J. Fuller 			return (ERANGE);
124677cb4d3eSLandon J. Fuller 
124777cb4d3eSLandon J. Fuller 		nbytes = sizeof(int16_t);
124877cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
124977cb4d3eSLandon J. Fuller 			*((int16_t *)outp) = (int16_t)intv.i64;
125077cb4d3eSLandon J. Fuller 		break;
125177cb4d3eSLandon J. Fuller 
125277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
125377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
125477cb4d3eSLandon J. Fuller 		if (intv.i64 < INT32_MIN || intv.i64 > INT32_MAX)
125577cb4d3eSLandon J. Fuller 			return (ERANGE);
125677cb4d3eSLandon J. Fuller 
125777cb4d3eSLandon J. Fuller 		nbytes = sizeof(int32_t);
125877cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
125977cb4d3eSLandon J. Fuller 			*((int32_t *)outp) = (int32_t)intv.i64;
126077cb4d3eSLandon J. Fuller 		break;
126177cb4d3eSLandon J. Fuller 
126277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
126377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
126477cb4d3eSLandon J. Fuller 		nbytes = sizeof(int64_t);
126577cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
126677cb4d3eSLandon J. Fuller 			*((int64_t *)outp) = intv.i64;
126777cb4d3eSLandon J. Fuller 		break;
126877cb4d3eSLandon J. Fuller 
126977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
127077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY: {
127177cb4d3eSLandon J. Fuller 		ssize_t len;
127277cb4d3eSLandon J. Fuller 
127377cb4d3eSLandon J. Fuller 		/* Attempt to write the entry + NUL */
127477cb4d3eSLandon J. Fuller 		if (otype_signed) {
127577cb4d3eSLandon J. Fuller 			len = snprintf(outp, limit, "%" PRId64, intv.i64);
127677cb4d3eSLandon J. Fuller 		} else {
127777cb4d3eSLandon J. Fuller 			len = snprintf(outp, limit, "%" PRIu64, intv.u64);
127877cb4d3eSLandon J. Fuller 		}
127977cb4d3eSLandon J. Fuller 
128077cb4d3eSLandon J. Fuller 		if (len < 0) {
128177cb4d3eSLandon J. Fuller 			BHND_NV_LOG("snprintf() failed: %zd\n", len);
128277cb4d3eSLandon J. Fuller 			return (EFTYPE);
128377cb4d3eSLandon J. Fuller 		}
128477cb4d3eSLandon J. Fuller 
128577cb4d3eSLandon J. Fuller 		/* Set total length to the formatted string length, plus
128677cb4d3eSLandon J. Fuller 		 * trailing NUL */
128777cb4d3eSLandon J. Fuller 		nbytes = len + 1;
128877cb4d3eSLandon J. Fuller 		break;
128977cb4d3eSLandon J. Fuller 	}
129077cb4d3eSLandon J. Fuller 
129177cb4d3eSLandon J. Fuller 	default:
129277cb4d3eSLandon J. Fuller 		BHND_NV_LOG("unknown type %s\n", bhnd_nvram_type_name(otype));
129377cb4d3eSLandon J. Fuller 		return (EFTYPE);
129477cb4d3eSLandon J. Fuller 	}
129577cb4d3eSLandon J. Fuller 
129677cb4d3eSLandon J. Fuller 	/* Provide required length */
129777cb4d3eSLandon J. Fuller 	*olen = nbytes;
129877cb4d3eSLandon J. Fuller 	if (limit < *olen) {
129977cb4d3eSLandon J. Fuller 		if (outp == NULL)
130077cb4d3eSLandon J. Fuller 			return (0);
130177cb4d3eSLandon J. Fuller 
130277cb4d3eSLandon J. Fuller 		return (ENOMEM);
130377cb4d3eSLandon J. Fuller 	}
130477cb4d3eSLandon J. Fuller 
130577cb4d3eSLandon J. Fuller 	return (0);
130677cb4d3eSLandon J. Fuller }
130777cb4d3eSLandon J. Fuller 
130877cb4d3eSLandon J. Fuller /**
130977cb4d3eSLandon J. Fuller  * Encode the given @p value as @p otype, writing the result to @p outp.
131077cb4d3eSLandon J. Fuller  *
131177cb4d3eSLandon J. Fuller  * @param		value	The value to be encoded.
131277cb4d3eSLandon J. Fuller  * @param[out]		outp	On success, the value will be written to this
131377cb4d3eSLandon J. Fuller  *				buffer. This argment may be NULL if the value is
131477cb4d3eSLandon J. Fuller  *				not desired.
131577cb4d3eSLandon J. Fuller  * @param[in,out]	olen	The capacity of @p outp. On success, will be set
131677cb4d3eSLandon J. Fuller  *				to the actual size of the requested value.
131777cb4d3eSLandon J. Fuller  * @param		otype	The data type to be written to @p outp.
131877cb4d3eSLandon J. Fuller  *
131977cb4d3eSLandon J. Fuller  * @retval 0		success
132077cb4d3eSLandon J. Fuller  * @retval ENOMEM	If the @p outp is non-NULL, and the provided @p olen
132177cb4d3eSLandon J. Fuller  *			is too small to hold the encoded value.
132277cb4d3eSLandon J. Fuller  * @retval EFTYPE	If value coercion from @p value to @p otype is
132377cb4d3eSLandon J. Fuller  *			impossible.
132477cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
132577cb4d3eSLandon J. Fuller  *			a @p otype representation.
132677cb4d3eSLandon J. Fuller  */
132777cb4d3eSLandon J. Fuller int
bhnd_nvram_val_encode(bhnd_nvram_val * value,void * outp,size_t * olen,bhnd_nvram_type otype)132858efe686SLandon J. Fuller bhnd_nvram_val_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
132977cb4d3eSLandon J. Fuller     bhnd_nvram_type otype)
133077cb4d3eSLandon J. Fuller {
133177cb4d3eSLandon J. Fuller 	/* Prefer format implementation */
13329be0790dSLandon J. Fuller 	if (value->fmt->op_encode != NULL)
133377cb4d3eSLandon J. Fuller 		return (value->fmt->op_encode(value, outp, olen, otype));
133477cb4d3eSLandon J. Fuller 
133577cb4d3eSLandon J. Fuller 	return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
133677cb4d3eSLandon J. Fuller }
133777cb4d3eSLandon J. Fuller 
133877cb4d3eSLandon J. Fuller /**
133977cb4d3eSLandon J. Fuller  * Encode the given @p value's element as @p otype, writing the result to
134077cb4d3eSLandon J. Fuller  * @p outp.
134177cb4d3eSLandon J. Fuller  *
1342*060f5c02SGordon Bergling  * @param		inp	The element to be encoded. Must be a value
134377cb4d3eSLandon J. Fuller  *				previously returned by bhnd_nvram_val_next()
134477cb4d3eSLandon J. Fuller  *				or bhnd_nvram_val_elem().
134577cb4d3eSLandon J. Fuller  * @param		ilen	The size of @p inp, as returned by
134677cb4d3eSLandon J. Fuller  *				bhnd_nvram_val_next() or bhnd_nvram_val_elem().
134777cb4d3eSLandon J. Fuller  * @param[out]		outp	On success, the value will be written to this
134877cb4d3eSLandon J. Fuller  *				buffer. This argment may be NULL if the value is
134977cb4d3eSLandon J. Fuller  *				not desired.
135077cb4d3eSLandon J. Fuller  * @param[in,out]	olen	The capacity of @p outp. On success, will be set
135177cb4d3eSLandon J. Fuller  *				to the actual size of the requested value.
135277cb4d3eSLandon J. Fuller  * @param		otype	The data type to be written to @p outp.
135377cb4d3eSLandon J. Fuller  *
135477cb4d3eSLandon J. Fuller  * @retval 0		success
135577cb4d3eSLandon J. Fuller  * @retval ENOMEM	If the @p outp is non-NULL, and the provided @p olen
135677cb4d3eSLandon J. Fuller  *			is too small to hold the encoded value.
135777cb4d3eSLandon J. Fuller  * @retval EFTYPE	If value coercion from @p value to @p otype is
135877cb4d3eSLandon J. Fuller  *			impossible.
135977cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
136077cb4d3eSLandon J. Fuller  *			a @p otype representation.
136177cb4d3eSLandon J. Fuller  */
136277cb4d3eSLandon J. Fuller int
bhnd_nvram_val_encode_elem(bhnd_nvram_val * value,const void * inp,size_t ilen,void * outp,size_t * olen,bhnd_nvram_type otype)136358efe686SLandon J. Fuller bhnd_nvram_val_encode_elem(bhnd_nvram_val *value, const void *inp,
136477cb4d3eSLandon J. Fuller     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
136577cb4d3eSLandon J. Fuller {
136677cb4d3eSLandon J. Fuller 	/* Prefer format implementation */
13679be0790dSLandon J. Fuller 	if (value->fmt->op_encode_elem != NULL) {
136877cb4d3eSLandon J. Fuller 		return (value->fmt->op_encode_elem(value, inp, ilen, outp,
136977cb4d3eSLandon J. Fuller 		    olen, otype));
137077cb4d3eSLandon J. Fuller 	}
137177cb4d3eSLandon J. Fuller 
137277cb4d3eSLandon J. Fuller 	return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen, outp,
137377cb4d3eSLandon J. Fuller 	    olen, otype));
137477cb4d3eSLandon J. Fuller }
137577cb4d3eSLandon J. Fuller 
137677cb4d3eSLandon J. Fuller /**
137777cb4d3eSLandon J. Fuller  * Return the type, size, and a pointer to the internal representation
137877cb4d3eSLandon J. Fuller  * of @p value.
137977cb4d3eSLandon J. Fuller  *
138077cb4d3eSLandon J. Fuller  * @param	value	The value to be queried.
138177cb4d3eSLandon J. Fuller  * @param[out]	olen	Size of the returned data, in bytes.
138277cb4d3eSLandon J. Fuller  * @param[out]	otype	Data type.
138377cb4d3eSLandon J. Fuller  */
138477cb4d3eSLandon J. Fuller const void *
bhnd_nvram_val_bytes(bhnd_nvram_val * value,size_t * olen,bhnd_nvram_type * otype)138558efe686SLandon J. Fuller bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
138677cb4d3eSLandon J. Fuller     bhnd_nvram_type *otype)
138777cb4d3eSLandon J. Fuller {
138877cb4d3eSLandon J. Fuller 	/* Provide type and length */
138977cb4d3eSLandon J. Fuller 	*otype = value->data_type;
139077cb4d3eSLandon J. Fuller 	*olen = value->data_len;
139177cb4d3eSLandon J. Fuller 
139277cb4d3eSLandon J. Fuller 	switch (value->data_storage) {
139377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
139477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_STATIC:
139577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_WEAK:
139677cb4d3eSLandon J. Fuller 		/* Return a pointer to external storage */
139777cb4d3eSLandon J. Fuller 		return (value->data.ptr);
139877cb4d3eSLandon J. Fuller 
139977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_INLINE:
140077cb4d3eSLandon J. Fuller 		/* Return a pointer to inline storage */
140177cb4d3eSLandon J. Fuller 		return (&value->data);
140277cb4d3eSLandon J. Fuller 
140377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_NONE:
140477cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("uninitialized value");
140577cb4d3eSLandon J. Fuller 	}
140677cb4d3eSLandon J. Fuller 
140777cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("unknown storage type: %d", value->data_storage);
140877cb4d3eSLandon J. Fuller }
140977cb4d3eSLandon J. Fuller 
141077cb4d3eSLandon J. Fuller /**
141177cb4d3eSLandon J. Fuller  * Iterate over all array elements in @p value.
141277cb4d3eSLandon J. Fuller  *
141377cb4d3eSLandon J. Fuller  * @param		value	The value to be iterated
141477cb4d3eSLandon J. Fuller  * @param		prev	A value pointer previously returned by
141577cb4d3eSLandon J. Fuller  *				bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
141677cb4d3eSLandon J. Fuller  *				or NULL to begin iteration at the first element.
14179be0790dSLandon J. Fuller  * @param[in,out]	olen	If @p prev is non-NULL, @p olen must be a
14189be0790dSLandon J. Fuller  *				pointer to the length previously returned by
141977cb4d3eSLandon J. Fuller  *				bhnd_nvram_val_next() or bhnd_nvram_val_elem().
142077cb4d3eSLandon J. Fuller  *				On success, will be set to the next element's
142177cb4d3eSLandon J. Fuller  *				length, in bytes.
142277cb4d3eSLandon J. Fuller  *
142377cb4d3eSLandon J. Fuller  * @retval non-NULL	A borrowed reference to the element data.
142477cb4d3eSLandon J. Fuller  * @retval NULL		If the end of the element array is reached.
142577cb4d3eSLandon J. Fuller  */
142677cb4d3eSLandon J. Fuller const void *
bhnd_nvram_val_next(bhnd_nvram_val * value,const void * prev,size_t * olen)14279be0790dSLandon J. Fuller bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *olen)
142877cb4d3eSLandon J. Fuller {
142977cb4d3eSLandon J. Fuller 	/* Prefer the format implementation */
14309be0790dSLandon J. Fuller 	if (value->fmt->op_next != NULL)
14319be0790dSLandon J. Fuller 		return (value->fmt->op_next(value, prev, olen));
143277cb4d3eSLandon J. Fuller 
14339be0790dSLandon J. Fuller 	return (bhnd_nvram_val_generic_next(value, prev, olen));
143477cb4d3eSLandon J. Fuller }
143577cb4d3eSLandon J. Fuller 
143677cb4d3eSLandon J. Fuller /**
1437eb686149SLandon J. Fuller  * Return the value's data type.
1438eb686149SLandon J. Fuller  *
1439eb686149SLandon J. Fuller  * @param	value	The value to be queried.
1440eb686149SLandon J. Fuller  */
1441eb686149SLandon J. Fuller bhnd_nvram_type
bhnd_nvram_val_type(bhnd_nvram_val * value)1442eb686149SLandon J. Fuller bhnd_nvram_val_type(bhnd_nvram_val *value)
1443eb686149SLandon J. Fuller {
1444eb686149SLandon J. Fuller 	return (value->data_type);
1445eb686149SLandon J. Fuller }
1446eb686149SLandon J. Fuller 
1447eb686149SLandon J. Fuller /**
144877cb4d3eSLandon J. Fuller  * Return value's element data type.
144977cb4d3eSLandon J. Fuller  *
145077cb4d3eSLandon J. Fuller  * @param	value	The value to be queried.
145177cb4d3eSLandon J. Fuller  */
145277cb4d3eSLandon J. Fuller bhnd_nvram_type
bhnd_nvram_val_elem_type(bhnd_nvram_val * value)145358efe686SLandon J. Fuller bhnd_nvram_val_elem_type(bhnd_nvram_val *value)
145477cb4d3eSLandon J. Fuller {
145577cb4d3eSLandon J. Fuller 	return (bhnd_nvram_base_type(value->data_type));
145677cb4d3eSLandon J. Fuller }
145777cb4d3eSLandon J. Fuller 
145877cb4d3eSLandon J. Fuller /**
145977cb4d3eSLandon J. Fuller  * Return the total number of elements represented by @p value.
146077cb4d3eSLandon J. Fuller  */
146177cb4d3eSLandon J. Fuller size_t
bhnd_nvram_val_nelem(bhnd_nvram_val * value)146258efe686SLandon J. Fuller bhnd_nvram_val_nelem(bhnd_nvram_val *value)
146377cb4d3eSLandon J. Fuller {
146477cb4d3eSLandon J. Fuller 	const void	*bytes;
146577cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 type;
146677cb4d3eSLandon J. Fuller 	size_t		 nelem, len;
146777cb4d3eSLandon J. Fuller 	int		 error;
146877cb4d3eSLandon J. Fuller 
146977cb4d3eSLandon J. Fuller 	/* Prefer format implementation */
14709be0790dSLandon J. Fuller 	if (value->fmt->op_nelem != NULL)
147177cb4d3eSLandon J. Fuller 		return (value->fmt->op_nelem(value));
147277cb4d3eSLandon J. Fuller 
147377cb4d3eSLandon J. Fuller 	/*
147477cb4d3eSLandon J. Fuller 	 * If a custom op_next() is defined, bhnd_nvram_value_nelem() almost
147577cb4d3eSLandon J. Fuller 	 * certainly cannot produce a valid element count; it assumes a standard
147677cb4d3eSLandon J. Fuller 	 * data format that may not apply when custom iteration is required.
147777cb4d3eSLandon J. Fuller 	 *
147877cb4d3eSLandon J. Fuller 	 * Instead, use bhnd_nvram_val_next() to parse the backing data and
147977cb4d3eSLandon J. Fuller 	 * produce a total count.
148077cb4d3eSLandon J. Fuller 	 */
14819be0790dSLandon J. Fuller 	if (value->fmt->op_next != NULL) {
148277cb4d3eSLandon J. Fuller 		const void *next;
148377cb4d3eSLandon J. Fuller 
148477cb4d3eSLandon J. Fuller 		next = NULL;
148577cb4d3eSLandon J. Fuller 		nelem = 0;
148677cb4d3eSLandon J. Fuller 		while ((next = bhnd_nvram_val_next(value, next, &len)) != NULL)
148777cb4d3eSLandon J. Fuller 			nelem++;
148877cb4d3eSLandon J. Fuller 
148977cb4d3eSLandon J. Fuller 		return (nelem);
149077cb4d3eSLandon J. Fuller 	}
149177cb4d3eSLandon J. Fuller 
149277cb4d3eSLandon J. Fuller 	/* Otherwise, compute the standard element count */
149377cb4d3eSLandon J. Fuller 	bytes = bhnd_nvram_val_bytes(value, &len, &type);
14949be0790dSLandon J. Fuller 	if ((error = bhnd_nvram_value_nelem(bytes, len, type, &nelem))) {
149577cb4d3eSLandon J. Fuller 		/* Should always succeed */
149677cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("error calculating element count for type '%s' "
149777cb4d3eSLandon J. Fuller 		    "with length %zu: %d\n", bhnd_nvram_type_name(type), len,
149877cb4d3eSLandon J. Fuller 		    error);
149977cb4d3eSLandon J. Fuller 	}
150077cb4d3eSLandon J. Fuller 
150177cb4d3eSLandon J. Fuller 	return (nelem);
150277cb4d3eSLandon J. Fuller }
150377cb4d3eSLandon J. Fuller 
150477cb4d3eSLandon J. Fuller /**
150577cb4d3eSLandon J. Fuller  * Generic implementation of bhnd_nvram_val_op_encode(), compatible with
150677cb4d3eSLandon J. Fuller  * all supported NVRAM data types.
150777cb4d3eSLandon J. Fuller  */
150877cb4d3eSLandon J. Fuller int
bhnd_nvram_val_generic_encode(bhnd_nvram_val * value,void * outp,size_t * olen,bhnd_nvram_type otype)150958efe686SLandon J. Fuller bhnd_nvram_val_generic_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
151077cb4d3eSLandon J. Fuller     bhnd_nvram_type otype)
151177cb4d3eSLandon J. Fuller {
151277cb4d3eSLandon J. Fuller 	const void	*inp;
151377cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 itype;
151477cb4d3eSLandon J. Fuller 	size_t		 ilen;
151577cb4d3eSLandon J. Fuller 	const void	*next;
151677cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype_base;
151777cb4d3eSLandon J. Fuller 	size_t		 limit, nelem, nbytes;
151877cb4d3eSLandon J. Fuller 	size_t		 next_len;
151977cb4d3eSLandon J. Fuller 	int		 error;
152077cb4d3eSLandon J. Fuller 
152177cb4d3eSLandon J. Fuller 	nbytes = 0;
152277cb4d3eSLandon J. Fuller 	nelem = 0;
152377cb4d3eSLandon J. Fuller 	otype_base = bhnd_nvram_base_type(otype);
15249be0790dSLandon J. Fuller 	inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
152577cb4d3eSLandon J. Fuller 
152677cb4d3eSLandon J. Fuller 	/*
15279be0790dSLandon J. Fuller 	 * Normally, an array type is not universally representable as
15289be0790dSLandon J. Fuller 	 * non-array type.
152977cb4d3eSLandon J. Fuller 	 *
15309be0790dSLandon J. Fuller 	 * As exceptions, we support conversion directly to/from:
15319be0790dSLandon J. Fuller 	 *	- CHAR_ARRAY/STRING:
15329be0790dSLandon J. Fuller 	 *		->STRING	Interpret the character array as a
153377cb4d3eSLandon J. Fuller 	 *			 	non-NUL-terminated string.
15349be0790dSLandon J. Fuller 	 *		->CHAR_ARRAY	Trim the trailing NUL from the string.
153577cb4d3eSLandon J. Fuller 	 */
15369be0790dSLandon J. Fuller #define	BHND_NV_IS_ISO_CONV(_lhs, _rhs)		\
15379be0790dSLandon J. Fuller 	((itype == BHND_NVRAM_TYPE_ ## _lhs &&	\
15389be0790dSLandon J. Fuller 	  otype == BHND_NVRAM_TYPE_ ## _rhs) ||	\
15399be0790dSLandon J. Fuller 	 (itype == BHND_NVRAM_TYPE_ ## _rhs &&	\
15409be0790dSLandon J. Fuller 	  otype == BHND_NVRAM_TYPE_ ## _lhs))
15419be0790dSLandon J. Fuller 
15429be0790dSLandon J. Fuller 	if (BHND_NV_IS_ISO_CONV(CHAR_ARRAY, STRING)) {
154377cb4d3eSLandon J. Fuller 		return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
154477cb4d3eSLandon J. Fuller 		    otype));
154577cb4d3eSLandon J. Fuller 	}
154677cb4d3eSLandon J. Fuller 
15479be0790dSLandon J. Fuller #undef	BHND_NV_IS_ISO_CONV
15489be0790dSLandon J. Fuller 
154977cb4d3eSLandon J. Fuller 	/*
155077cb4d3eSLandon J. Fuller 	 * If both input and output are non-array types, try to encode them
155177cb4d3eSLandon J. Fuller 	 * without performing element iteration.
155277cb4d3eSLandon J. Fuller 	 */
155377cb4d3eSLandon J. Fuller 	if (!bhnd_nvram_is_array_type(itype) &&
155477cb4d3eSLandon J. Fuller 	    !bhnd_nvram_is_array_type(otype))
155577cb4d3eSLandon J. Fuller 	{
155677cb4d3eSLandon J. Fuller 		return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
155777cb4d3eSLandon J. Fuller 		    otype));
155877cb4d3eSLandon J. Fuller 	}
155977cb4d3eSLandon J. Fuller 
156077cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
156177cb4d3eSLandon J. Fuller 	if (outp != NULL)
156277cb4d3eSLandon J. Fuller 		limit = *olen;
156377cb4d3eSLandon J. Fuller 	else
156477cb4d3eSLandon J. Fuller 		limit = 0;
156577cb4d3eSLandon J. Fuller 
156677cb4d3eSLandon J. Fuller 	/* Iterate over our array elements and encode as the requested
156777cb4d3eSLandon J. Fuller 	 * type */
156877cb4d3eSLandon J. Fuller 	next = NULL;
156977cb4d3eSLandon J. Fuller 	while ((next = bhnd_nvram_val_next(value, next, &next_len))) {
157077cb4d3eSLandon J. Fuller 		void			*elem_outp;
157177cb4d3eSLandon J. Fuller 		size_t			 elem_nbytes;
157277cb4d3eSLandon J. Fuller 
157377cb4d3eSLandon J. Fuller 		/* If the output type is not an array type, we can only encode
157477cb4d3eSLandon J. Fuller 		 * one element */
157577cb4d3eSLandon J. Fuller 		nelem++;
157677cb4d3eSLandon J. Fuller 		if (nelem > 1 && !bhnd_nvram_is_array_type(otype)) {
157777cb4d3eSLandon J. Fuller 			return (EFTYPE);
157877cb4d3eSLandon J. Fuller 		}
157977cb4d3eSLandon J. Fuller 
158077cb4d3eSLandon J. Fuller 		/* Determine output offset / limit */
158177cb4d3eSLandon J. Fuller 		if (nbytes >= limit) {
158277cb4d3eSLandon J. Fuller 			elem_nbytes = 0;
158377cb4d3eSLandon J. Fuller 			elem_outp = NULL;
158477cb4d3eSLandon J. Fuller 		} else {
158577cb4d3eSLandon J. Fuller 			elem_nbytes = limit - nbytes;
158677cb4d3eSLandon J. Fuller 			elem_outp = (uint8_t *)outp + nbytes;
158777cb4d3eSLandon J. Fuller 		}
158877cb4d3eSLandon J. Fuller 
158977cb4d3eSLandon J. Fuller 		/* Attempt encode */
159077cb4d3eSLandon J. Fuller 		error = bhnd_nvram_val_encode_elem(value, next, next_len,
159177cb4d3eSLandon J. Fuller 		    elem_outp, &elem_nbytes, otype_base);
159277cb4d3eSLandon J. Fuller 
159377cb4d3eSLandon J. Fuller 		/* If encoding failed for any reason other than ENOMEM (which
159477cb4d3eSLandon J. Fuller 		 * we'll detect and report below), return immediately */
159577cb4d3eSLandon J. Fuller 		if (error && error != ENOMEM)
159677cb4d3eSLandon J. Fuller 			return (error);
159777cb4d3eSLandon J. Fuller 
159877cb4d3eSLandon J. Fuller 		/* Add to total length */
159977cb4d3eSLandon J. Fuller 		if (SIZE_MAX - nbytes < elem_nbytes)
160077cb4d3eSLandon J. Fuller 			return (EFTYPE); /* would overflow size_t */
160177cb4d3eSLandon J. Fuller 
160277cb4d3eSLandon J. Fuller 		nbytes += elem_nbytes;
160377cb4d3eSLandon J. Fuller 	}
160477cb4d3eSLandon J. Fuller 
160577cb4d3eSLandon J. Fuller 	/* Provide the actual length */
160677cb4d3eSLandon J. Fuller 	*olen = nbytes;
160777cb4d3eSLandon J. Fuller 
160877cb4d3eSLandon J. Fuller 	/* If no output was requested, nothing left to do */
160977cb4d3eSLandon J. Fuller 	if (outp == NULL)
161077cb4d3eSLandon J. Fuller 		return (0);
161177cb4d3eSLandon J. Fuller 
161277cb4d3eSLandon J. Fuller 	/* Otherwise, report a memory error if the output buffer was too
161377cb4d3eSLandon J. Fuller 	 * small */
161477cb4d3eSLandon J. Fuller 	if (limit < nbytes)
161577cb4d3eSLandon J. Fuller 		return (ENOMEM);
161677cb4d3eSLandon J. Fuller 
161777cb4d3eSLandon J. Fuller 	return (0);
161877cb4d3eSLandon J. Fuller }
161977cb4d3eSLandon J. Fuller 
162077cb4d3eSLandon J. Fuller /**
162177cb4d3eSLandon J. Fuller  * Generic implementation of bhnd_nvram_val_op_encode_elem(), compatible with
162277cb4d3eSLandon J. Fuller  * all supported NVRAM data types.
162377cb4d3eSLandon J. Fuller  */
162477cb4d3eSLandon J. Fuller int
bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val * value,const void * inp,size_t ilen,void * outp,size_t * olen,bhnd_nvram_type otype)162558efe686SLandon J. Fuller bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
162677cb4d3eSLandon J. Fuller     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
162777cb4d3eSLandon J. Fuller {
162877cb4d3eSLandon J. Fuller 	bhnd_nvram_type itype;
162977cb4d3eSLandon J. Fuller 
163077cb4d3eSLandon J. Fuller 	itype = bhnd_nvram_val_elem_type(value);
163177cb4d3eSLandon J. Fuller 	switch (itype) {
16326cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
16336cffadf0SLandon J. Fuller 		return (bhnd_nvram_val_encode_null(inp, ilen, itype, outp, olen,
16346cffadf0SLandon J. Fuller 		    otype));
16356cffadf0SLandon J. Fuller 
16366cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
16376cffadf0SLandon J. Fuller 		return (bhnd_nvram_val_encode_data(inp, ilen, itype, outp,
16386cffadf0SLandon J. Fuller 		    olen, otype));
16396cffadf0SLandon J. Fuller 
164077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
164177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
16429be0790dSLandon J. Fuller 		return (bhnd_nvram_val_encode_string(inp, ilen, itype, outp,
16439be0790dSLandon J. Fuller 		    olen, otype));
164477cb4d3eSLandon J. Fuller 
16456cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
16466cffadf0SLandon J. Fuller 		return (bhnd_nvram_val_encode_bool(inp, ilen, itype, outp, olen,
16476cffadf0SLandon J. Fuller 		    otype));
16486cffadf0SLandon J. Fuller 
164977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
165077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
165177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
165277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
165377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
165477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
165577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
165677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
16579be0790dSLandon J. Fuller 		return (bhnd_nvram_val_encode_int(inp, ilen, itype, outp, olen,
16589be0790dSLandon J. Fuller 		    otype));
165977cb4d3eSLandon J. Fuller 	default:
166077cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("missing encode_elem() implementation");
166177cb4d3eSLandon J. Fuller 	}
166277cb4d3eSLandon J. Fuller }
166377cb4d3eSLandon J. Fuller 
166477cb4d3eSLandon J. Fuller /**
166577cb4d3eSLandon J. Fuller  * Generic implementation of bhnd_nvram_val_op_next(), compatible with
166677cb4d3eSLandon J. Fuller  * all supported NVRAM data types.
166777cb4d3eSLandon J. Fuller  */
166877cb4d3eSLandon J. Fuller const void *
bhnd_nvram_val_generic_next(bhnd_nvram_val * value,const void * prev,size_t * olen)166958efe686SLandon J. Fuller bhnd_nvram_val_generic_next(bhnd_nvram_val *value, const void *prev,
16709be0790dSLandon J. Fuller     size_t *olen)
167177cb4d3eSLandon J. Fuller {
167277cb4d3eSLandon J. Fuller 	const uint8_t	*inp;
167377cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 itype;
167477cb4d3eSLandon J. Fuller 	size_t		 ilen;
167577cb4d3eSLandon J. Fuller 
16769be0790dSLandon J. Fuller 	/* Iterate over the backing representation */
167777cb4d3eSLandon J. Fuller 	inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
16789be0790dSLandon J. Fuller 	return (bhnd_nvram_value_array_next(inp, ilen, itype, prev, olen));
167977cb4d3eSLandon J. Fuller }
168077cb4d3eSLandon J. Fuller 
168177cb4d3eSLandon J. Fuller /**
168277cb4d3eSLandon J. Fuller  * Initialize the representation of @p value with @p ptr.
168377cb4d3eSLandon J. Fuller  *
168477cb4d3eSLandon J. Fuller  * @param	value	The value to be initialized.
168577cb4d3eSLandon J. Fuller  * @param	inp	The external representation.
168677cb4d3eSLandon J. Fuller  * @param	ilen	The external representation length, in bytes.
168777cb4d3eSLandon J. Fuller  * @param	itype	The external representation's data type.
168877cb4d3eSLandon J. Fuller  * @param	flags	Value flags.
168977cb4d3eSLandon J. Fuller  *
169077cb4d3eSLandon J. Fuller  * @retval 0		success.
169177cb4d3eSLandon J. Fuller  * @retval ENOMEM	if allocation fails
169277cb4d3eSLandon J. Fuller  * @retval EFTYPE	if @p itype is not an array type, and @p ilen is not
169377cb4d3eSLandon J. Fuller  *			equal to the size of a single element of @p itype.
169477cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
169577cb4d3eSLandon J. Fuller  *			@p itype.
169677cb4d3eSLandon J. Fuller  */
169777cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_set(bhnd_nvram_val * value,const void * inp,size_t ilen,bhnd_nvram_type itype,uint32_t flags)169858efe686SLandon J. Fuller bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, size_t ilen,
169977cb4d3eSLandon J. Fuller     bhnd_nvram_type itype, uint32_t flags)
170077cb4d3eSLandon J. Fuller {
170177cb4d3eSLandon J. Fuller 	void	*bytes;
17029be0790dSLandon J. Fuller 	int	 error;
170377cb4d3eSLandon J. Fuller 
170477cb4d3eSLandon J. Fuller 	BHND_NVRAM_VAL_ASSERT_EMPTY(value);
170577cb4d3eSLandon J. Fuller 
17069be0790dSLandon J. Fuller 	/* Validate alignment */
17079be0790dSLandon J. Fuller 	if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
17089be0790dSLandon J. Fuller 		return (error);
17099be0790dSLandon J. Fuller 
171077cb4d3eSLandon J. Fuller 	/* Reference the external data */
171177cb4d3eSLandon J. Fuller 	if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
171277cb4d3eSLandon J. Fuller 	    (flags & BHND_NVRAM_VAL_STATIC_DATA))
171377cb4d3eSLandon J. Fuller 	{
17149be0790dSLandon J. Fuller 		if (flags & BHND_NVRAM_VAL_STATIC_DATA)
171577cb4d3eSLandon J. Fuller 			value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
17169be0790dSLandon J. Fuller 		else
17179be0790dSLandon J. Fuller 			value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
171877cb4d3eSLandon J. Fuller 
171977cb4d3eSLandon J. Fuller 		value->data.ptr = inp;
172077cb4d3eSLandon J. Fuller 		value->data_type = itype;
172177cb4d3eSLandon J. Fuller 		value->data_len = ilen;
172277cb4d3eSLandon J. Fuller 		return (0);
172377cb4d3eSLandon J. Fuller 	}
172477cb4d3eSLandon J. Fuller 
172577cb4d3eSLandon J. Fuller 	/* Fetch reference to (or allocate) an appropriately sized buffer */
172677cb4d3eSLandon J. Fuller 	bytes = bhnd_nvram_val_alloc_bytes(value, ilen, itype, flags);
172777cb4d3eSLandon J. Fuller 	if (bytes == NULL)
172877cb4d3eSLandon J. Fuller 		return (ENOMEM);
172977cb4d3eSLandon J. Fuller 
173077cb4d3eSLandon J. Fuller 	/* Copy data */
173177cb4d3eSLandon J. Fuller 	memcpy(bytes, inp, ilen);
173277cb4d3eSLandon J. Fuller 
173377cb4d3eSLandon J. Fuller 	return (0);
173477cb4d3eSLandon J. Fuller }
173577cb4d3eSLandon J. Fuller 
173677cb4d3eSLandon J. Fuller /**
173777cb4d3eSLandon J. Fuller  * Initialize the internal inline representation of @p value with a copy of
173877cb4d3eSLandon J. Fuller  * the data referenced by @p inp of @p itype.
173977cb4d3eSLandon J. Fuller  *
174077cb4d3eSLandon J. Fuller  * If @p inp is NULL, @p itype and @p ilen will be validated, but no data will
174177cb4d3eSLandon J. Fuller  * be copied.
174277cb4d3eSLandon J. Fuller  *
174377cb4d3eSLandon J. Fuller  * @param	value	The value to be initialized.
174477cb4d3eSLandon J. Fuller  * @param	inp	The input data to be copied, or NULL to verify
174577cb4d3eSLandon J. Fuller  *			that data of @p ilen and @p itype can be represented
174677cb4d3eSLandon J. Fuller  *			inline.
174777cb4d3eSLandon J. Fuller  * @param	ilen	The size of the external buffer to be allocated.
174877cb4d3eSLandon J. Fuller  * @param	itype	The type of the external buffer to be allocated.
174977cb4d3eSLandon J. Fuller  *
175077cb4d3eSLandon J. Fuller  * @retval 0		success
175177cb4d3eSLandon J. Fuller  * @retval ENOMEM	if @p ilen is too large to be represented inline.
175277cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
175377cb4d3eSLandon J. Fuller  *			@p itype.
175477cb4d3eSLandon J. Fuller  */
175577cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_set_inline(bhnd_nvram_val * value,const void * inp,size_t ilen,bhnd_nvram_type itype)175658efe686SLandon J. Fuller bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen,
175777cb4d3eSLandon J. Fuller     bhnd_nvram_type itype)
175877cb4d3eSLandon J. Fuller {
175977cb4d3eSLandon J. Fuller 	BHND_NVRAM_VAL_ASSERT_EMPTY(value);
176077cb4d3eSLandon J. Fuller 
176177cb4d3eSLandon J. Fuller #define	NV_STORE_INIT_INLINE()	do {					\
176277cb4d3eSLandon J. Fuller 	value->data_len = ilen;						\
17639be0790dSLandon J. Fuller 	value->data_type = itype;					\
176477cb4d3eSLandon J. Fuller } while(0)
176577cb4d3eSLandon J. Fuller 
176677cb4d3eSLandon J. Fuller #define	NV_STORE_INLINE(_type, _dest)	do {				\
176777cb4d3eSLandon J. Fuller 	if (ilen != sizeof(_type))					\
176877cb4d3eSLandon J. Fuller 		return (EFAULT);					\
176977cb4d3eSLandon J. Fuller 									\
177077cb4d3eSLandon J. Fuller 	if (inp != NULL) {						\
177177cb4d3eSLandon J. Fuller 		value->data._dest[0] = *(const _type *)inp;		\
177277cb4d3eSLandon J. Fuller 		NV_STORE_INIT_INLINE();					\
177377cb4d3eSLandon J. Fuller 	}								\
177477cb4d3eSLandon J. Fuller } while (0)
177577cb4d3eSLandon J. Fuller 
177677cb4d3eSLandon J. Fuller #define	NV_COPY_ARRRAY_INLINE(_type, _dest)	do {		\
177777cb4d3eSLandon J. Fuller 	if (ilen % sizeof(_type) != 0)				\
177877cb4d3eSLandon J. Fuller 		return (EFAULT);				\
177977cb4d3eSLandon J. Fuller 								\
178077cb4d3eSLandon J. Fuller 	if (ilen > nitems(value->data. _dest))			\
178177cb4d3eSLandon J. Fuller 		return (ENOMEM);				\
178277cb4d3eSLandon J. Fuller 								\
178377cb4d3eSLandon J. Fuller 	if (inp == NULL)					\
178477cb4d3eSLandon J. Fuller 		return (0);					\
178577cb4d3eSLandon J. Fuller 								\
178677cb4d3eSLandon J. Fuller 	memcpy(&value->data._dest, inp, ilen);			\
178777cb4d3eSLandon J. Fuller 	if (inp != NULL) {					\
178877cb4d3eSLandon J. Fuller 		memcpy(&value->data._dest, inp, ilen);		\
178977cb4d3eSLandon J. Fuller 		NV_STORE_INIT_INLINE();				\
179077cb4d3eSLandon J. Fuller 	}							\
179177cb4d3eSLandon J. Fuller } while (0)
179277cb4d3eSLandon J. Fuller 
179377cb4d3eSLandon J. Fuller 	/* Attempt to copy to inline storage */
179477cb4d3eSLandon J. Fuller 	switch (itype) {
17956cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
17966cffadf0SLandon J. Fuller 		if (ilen != 0)
17976cffadf0SLandon J. Fuller 			return (EFAULT);
17986cffadf0SLandon J. Fuller 
17996cffadf0SLandon J. Fuller 		/* Nothing to copy */
18006cffadf0SLandon J. Fuller 		NV_STORE_INIT_INLINE();
18016cffadf0SLandon J. Fuller 		return (0);
18026cffadf0SLandon J. Fuller 
180377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
180477cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint8_t, ch);
180577cb4d3eSLandon J. Fuller 		return (0);
180677cb4d3eSLandon J. Fuller 
18076cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
18086cffadf0SLandon J. Fuller 		NV_STORE_INLINE(bhnd_nvram_bool_t, b);
18096cffadf0SLandon J. Fuller 		return(0);
18106cffadf0SLandon J. Fuller 
181177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
181277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
181377cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint8_t, u8);
181477cb4d3eSLandon J. Fuller 		return (0);
181577cb4d3eSLandon J. Fuller 
181677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
181777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
181877cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint16_t, u16);
181977cb4d3eSLandon J. Fuller 		return (0);
182077cb4d3eSLandon J. Fuller 
182177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
182277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
182377cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint32_t, u32);
182477cb4d3eSLandon J. Fuller 		return (0);
182577cb4d3eSLandon J. Fuller 
182677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
182777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
182877cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint32_t, u32);
182977cb4d3eSLandon J. Fuller 		return (0);
183077cb4d3eSLandon J. Fuller 
183177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
183277cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint8_t, ch);
183377cb4d3eSLandon J. Fuller 		return (0);
183477cb4d3eSLandon J. Fuller 
18356cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
183677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
183777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
183877cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint8_t, u8);
183977cb4d3eSLandon J. Fuller 		return (0);
184077cb4d3eSLandon J. Fuller 
184177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
184277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
184377cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint16_t, u16);
184477cb4d3eSLandon J. Fuller 		return (0);
184577cb4d3eSLandon J. Fuller 
184677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
184777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
184877cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint32_t, u32);
184977cb4d3eSLandon J. Fuller 		return (0);
185077cb4d3eSLandon J. Fuller 
185177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
185277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
185377cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint64_t, u64);
185477cb4d3eSLandon J. Fuller 		return (0);
185577cb4d3eSLandon J. Fuller 
18566cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
18576cffadf0SLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(bhnd_nvram_bool_t, b);
18586cffadf0SLandon J. Fuller 		return(0);
18596cffadf0SLandon J. Fuller 
186077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
186177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
186277cb4d3eSLandon J. Fuller 		if (ilen > sizeof(value->data.ch))
186377cb4d3eSLandon J. Fuller 			return (ENOMEM);
186477cb4d3eSLandon J. Fuller 
186577cb4d3eSLandon J. Fuller 		if (inp != NULL) {
186677cb4d3eSLandon J. Fuller 			memcpy(&value->data.ch, inp, ilen);
186777cb4d3eSLandon J. Fuller 			NV_STORE_INIT_INLINE();
186877cb4d3eSLandon J. Fuller 		}
186977cb4d3eSLandon J. Fuller 
187077cb4d3eSLandon J. Fuller 		return (0);
187177cb4d3eSLandon J. Fuller 	}
187277cb4d3eSLandon J. Fuller 
187377cb4d3eSLandon J. Fuller #undef	NV_STORE_INIT_INLINE
187477cb4d3eSLandon J. Fuller #undef	NV_STORE_INLINE
187577cb4d3eSLandon J. Fuller #undef	NV_COPY_ARRRAY_INLINE
187677cb4d3eSLandon J. Fuller 
187777cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("unknown data type %d", itype);
187877cb4d3eSLandon J. Fuller }
187977cb4d3eSLandon J. Fuller 
188077cb4d3eSLandon J. Fuller /**
188177cb4d3eSLandon J. Fuller  * Initialize the internal representation of @p value with a buffer allocation
188277cb4d3eSLandon J. Fuller  * of @p len and @p itype, returning a pointer to the allocated buffer.
188377cb4d3eSLandon J. Fuller  *
188477cb4d3eSLandon J. Fuller  * If a buffer of @p len and @p itype can be represented inline, no
188577cb4d3eSLandon J. Fuller  * external buffer will be allocated, and instead a pointer to the inline
188677cb4d3eSLandon J. Fuller  * data representation will be returned.
188777cb4d3eSLandon J. Fuller  *
188877cb4d3eSLandon J. Fuller  * @param	value	The value to be initialized.
188977cb4d3eSLandon J. Fuller  * @param	ilen	The size of the external buffer to be allocated.
189077cb4d3eSLandon J. Fuller  * @param	itype	The type of the external buffer to be allocated.
189177cb4d3eSLandon J. Fuller  * @param	flags	Value flags.
189277cb4d3eSLandon J. Fuller  *
189377cb4d3eSLandon J. Fuller  * @retval non-null	The newly allocated buffer.
189477cb4d3eSLandon J. Fuller  * @retval NULL		If allocation failed.
189577cb4d3eSLandon J. Fuller  * @retval NULL		If @p value is an externally allocated instance.
189677cb4d3eSLandon J. Fuller  */
189777cb4d3eSLandon J. Fuller static void *
bhnd_nvram_val_alloc_bytes(bhnd_nvram_val * value,size_t ilen,bhnd_nvram_type itype,uint32_t flags)189858efe686SLandon J. Fuller bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
189977cb4d3eSLandon J. Fuller     bhnd_nvram_type itype, uint32_t flags)
190077cb4d3eSLandon J. Fuller {
190177cb4d3eSLandon J. Fuller 	void *ptr;
190277cb4d3eSLandon J. Fuller 
190377cb4d3eSLandon J. Fuller 	BHND_NVRAM_VAL_ASSERT_EMPTY(value);
190477cb4d3eSLandon J. Fuller 
190577cb4d3eSLandon J. Fuller 	/* Can we use inline storage? */
190677cb4d3eSLandon J. Fuller 	if (bhnd_nvram_val_set_inline(value, NULL, ilen, itype) == 0) {
190777cb4d3eSLandon J. Fuller 		BHND_NV_ASSERT(sizeof(value->data) >= ilen,
190877cb4d3eSLandon J. Fuller 		    ("ilen exceeds inline storage"));
190977cb4d3eSLandon J. Fuller 
191077cb4d3eSLandon J. Fuller 		value->data_type = itype;
191177cb4d3eSLandon J. Fuller 		value->data_len = ilen;
191277cb4d3eSLandon J. Fuller 		value->data_storage = BHND_NVRAM_VAL_DATA_INLINE;
191377cb4d3eSLandon J. Fuller 		return (&value->data);
191477cb4d3eSLandon J. Fuller 	}
191577cb4d3eSLandon J. Fuller 
191677cb4d3eSLandon J. Fuller 	/* Is allocation permitted? */
191777cb4d3eSLandon J. Fuller 	if (!(flags & BHND_NVRAM_VAL_DYNAMIC))
191877cb4d3eSLandon J. Fuller 		return (NULL);
191977cb4d3eSLandon J. Fuller 
192077cb4d3eSLandon J. Fuller 	/* Allocate external storage */
192177cb4d3eSLandon J. Fuller 	if ((ptr = bhnd_nv_malloc(ilen)) == NULL)
192277cb4d3eSLandon J. Fuller 		return (NULL);
192377cb4d3eSLandon J. Fuller 
192477cb4d3eSLandon J. Fuller 	value->data.ptr = ptr;
192577cb4d3eSLandon J. Fuller 	value->data_len = ilen;
192677cb4d3eSLandon J. Fuller 	value->data_type = itype;
192777cb4d3eSLandon J. Fuller 	value->data_storage = BHND_NVRAM_VAL_DATA_EXT_ALLOC;
192877cb4d3eSLandon J. Fuller 
192977cb4d3eSLandon J. Fuller 	return (ptr);
193077cb4d3eSLandon J. Fuller }
1931