xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_value.c (revision 77cb4d3e5016a2fd090d07ed3e01a199723641d9)
1*77cb4d3eSLandon J. Fuller /*-
2*77cb4d3eSLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
3*77cb4d3eSLandon J. Fuller  * All rights reserved.
4*77cb4d3eSLandon J. Fuller  *
5*77cb4d3eSLandon J. Fuller  * Redistribution and use in source and binary forms, with or without
6*77cb4d3eSLandon J. Fuller  * modification, are permitted provided that the following conditions
7*77cb4d3eSLandon J. Fuller  * are met:
8*77cb4d3eSLandon J. Fuller  * 1. Redistributions of source code must retain the above copyright
9*77cb4d3eSLandon J. Fuller  *    notice, this list of conditions and the following disclaimer,
10*77cb4d3eSLandon J. Fuller  *    without modification.
11*77cb4d3eSLandon J. Fuller  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12*77cb4d3eSLandon J. Fuller  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13*77cb4d3eSLandon J. Fuller  *    redistribution must be conditioned upon including a substantially
14*77cb4d3eSLandon J. Fuller  *    similar Disclaimer requirement for further binary redistribution.
15*77cb4d3eSLandon J. Fuller  *
16*77cb4d3eSLandon J. Fuller  * NO WARRANTY
17*77cb4d3eSLandon J. Fuller  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*77cb4d3eSLandon J. Fuller  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*77cb4d3eSLandon J. Fuller  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20*77cb4d3eSLandon J. Fuller  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21*77cb4d3eSLandon J. Fuller  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22*77cb4d3eSLandon J. Fuller  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*77cb4d3eSLandon J. Fuller  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*77cb4d3eSLandon J. Fuller  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*77cb4d3eSLandon J. Fuller  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*77cb4d3eSLandon J. Fuller  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27*77cb4d3eSLandon J. Fuller  * THE POSSIBILITY OF SUCH DAMAGES.
28*77cb4d3eSLandon J. Fuller  */
29*77cb4d3eSLandon J. Fuller 
30*77cb4d3eSLandon J. Fuller #include <sys/cdefs.h>
31*77cb4d3eSLandon J. Fuller __FBSDID("$FreeBSD$");
32*77cb4d3eSLandon J. Fuller 
33*77cb4d3eSLandon J. Fuller #include <sys/param.h>
34*77cb4d3eSLandon J. Fuller #include <sys/sbuf.h>
35*77cb4d3eSLandon J. Fuller 
36*77cb4d3eSLandon J. Fuller #ifdef _KERNEL
37*77cb4d3eSLandon J. Fuller 
38*77cb4d3eSLandon J. Fuller #include <sys/kernel.h>
39*77cb4d3eSLandon J. Fuller #include <sys/malloc.h>
40*77cb4d3eSLandon J. Fuller #include <sys/systm.h>
41*77cb4d3eSLandon J. Fuller 
42*77cb4d3eSLandon J. Fuller #include <machine/_inttypes.h>
43*77cb4d3eSLandon J. Fuller 
44*77cb4d3eSLandon J. Fuller #else /* !_KERNEL */
45*77cb4d3eSLandon J. Fuller 
46*77cb4d3eSLandon J. Fuller #include <inttypes.h>
47*77cb4d3eSLandon J. Fuller #include <errno.h>
48*77cb4d3eSLandon J. Fuller #include <stdlib.h>
49*77cb4d3eSLandon J. Fuller #include <string.h>
50*77cb4d3eSLandon J. Fuller 
51*77cb4d3eSLandon J. Fuller #endif /* _KERNEL */
52*77cb4d3eSLandon J. Fuller 
53*77cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
54*77cb4d3eSLandon J. Fuller 
55*77cb4d3eSLandon J. Fuller #include "bhnd_nvram_valuevar.h"
56*77cb4d3eSLandon J. Fuller 
57*77cb4d3eSLandon J. Fuller 
58*77cb4d3eSLandon J. Fuller static void	*bhnd_nvram_val_alloc_bytes(bhnd_nvram_val_t *value,
59*77cb4d3eSLandon J. Fuller 					    size_t ilen, bhnd_nvram_type itype,
60*77cb4d3eSLandon J. Fuller 					    uint32_t flags);
61*77cb4d3eSLandon J. Fuller static int	 bhnd_nvram_val_set(bhnd_nvram_val_t *value, const void *inp,
62*77cb4d3eSLandon J. Fuller 				    size_t ilen, bhnd_nvram_type itype,
63*77cb4d3eSLandon J. Fuller 				    uint32_t flags);
64*77cb4d3eSLandon J. Fuller static int	 bhnd_nvram_val_set_inline(bhnd_nvram_val_t *value,
65*77cb4d3eSLandon J. Fuller 		     const void *inp, size_t ilen, bhnd_nvram_type itype);
66*77cb4d3eSLandon J. Fuller 
67*77cb4d3eSLandon J. Fuller #define	BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage)		\
68*77cb4d3eSLandon J. Fuller 	(bhnd_nvram_val_t) {					\
69*77cb4d3eSLandon J. Fuller 		.refs = 1,					\
70*77cb4d3eSLandon J. Fuller 		.val_storage = _storage,			\
71*77cb4d3eSLandon J. Fuller 		.fmt = _fmt,					\
72*77cb4d3eSLandon J. Fuller 		.data_storage = BHND_NVRAM_VAL_DATA_NONE,	\
73*77cb4d3eSLandon J. Fuller 	};
74*77cb4d3eSLandon J. Fuller 
75*77cb4d3eSLandon J. Fuller 
76*77cb4d3eSLandon J. Fuller /** Assert that @p value's backing representation state has initialized
77*77cb4d3eSLandon J. Fuller  *  as empty. */
78*77cb4d3eSLandon J. Fuller #define	BHND_NVRAM_VAL_ASSERT_EMPTY(_value)			\
79*77cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(						\
80*77cb4d3eSLandon J. Fuller 	    value->data_storage == BHND_NVRAM_VAL_DATA_NONE &&	\
81*77cb4d3eSLandon J. Fuller 	    value->data_len == 0 &&				\
82*77cb4d3eSLandon J. Fuller 	    value->data.ptr == NULL,				\
83*77cb4d3eSLandon J. Fuller 	    ("previously initialized value"))
84*77cb4d3eSLandon J. Fuller 
85*77cb4d3eSLandon J. Fuller /* Common initialization support for bhnd_nvram_val_init() and
86*77cb4d3eSLandon J. Fuller  * bhnd_nvram_val_new() */
87*77cb4d3eSLandon J. Fuller static int
88*77cb4d3eSLandon J. Fuller bhnd_nvram_val_init_common(bhnd_nvram_val_t *value, bhnd_nvram_val_storage_t
89*77cb4d3eSLandon J. Fuller     val_storage, const bhnd_nvram_val_fmt_t *fmt, const void *inp, size_t ilen,
90*77cb4d3eSLandon J. Fuller     bhnd_nvram_type itype, uint32_t flags)
91*77cb4d3eSLandon J. Fuller {
92*77cb4d3eSLandon J. Fuller 	void		*outp;
93*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype;
94*77cb4d3eSLandon J. Fuller 	size_t		 olen;
95*77cb4d3eSLandon J. Fuller 	int		 error;
96*77cb4d3eSLandon J. Fuller 
97*77cb4d3eSLandon J. Fuller 	/* Determine expected data type, and allow the format to delegate to
98*77cb4d3eSLandon J. Fuller 	 * a new format instance */
99*77cb4d3eSLandon J. Fuller 	if (fmt != NULL && fmt->op_filter != NULL) {
100*77cb4d3eSLandon J. Fuller 		const bhnd_nvram_val_fmt_t *nfmt = fmt;
101*77cb4d3eSLandon J. Fuller 
102*77cb4d3eSLandon J. Fuller 		/* Use the filter function to determine whether direct
103*77cb4d3eSLandon J. Fuller 		 * initialization from is itype permitted */
104*77cb4d3eSLandon J. Fuller 		error = fmt->op_filter(&nfmt, inp, ilen, itype);
105*77cb4d3eSLandon J. Fuller 		if (error)
106*77cb4d3eSLandon J. Fuller 			return (error);
107*77cb4d3eSLandon J. Fuller 
108*77cb4d3eSLandon J. Fuller 		/* Retry initialization with new format? */
109*77cb4d3eSLandon J. Fuller 		if (nfmt != fmt) {
110*77cb4d3eSLandon J. Fuller 			return (bhnd_nvram_val_init_common(value, val_storage,
111*77cb4d3eSLandon J. Fuller 			    nfmt, inp, ilen, itype, flags));
112*77cb4d3eSLandon J. Fuller 		}
113*77cb4d3eSLandon J. Fuller 
114*77cb4d3eSLandon J. Fuller 		/* Value can be initialized with provided input type */
115*77cb4d3eSLandon J. Fuller 		otype = itype;
116*77cb4d3eSLandon J. Fuller 
117*77cb4d3eSLandon J. Fuller 	} else if (fmt != NULL) {
118*77cb4d3eSLandon J. Fuller 		/* Value must be initialized with the format's native
119*77cb4d3eSLandon J. Fuller 		 * type */
120*77cb4d3eSLandon J. Fuller 		otype = fmt->native_type;
121*77cb4d3eSLandon J. Fuller 
122*77cb4d3eSLandon J. Fuller 	} else {
123*77cb4d3eSLandon J. Fuller 		/* No format specified; we can initialize directly from the
124*77cb4d3eSLandon J. Fuller 		 * input data, and we'll handle all format operations
125*77cb4d3eSLandon J. Fuller 		 * internally. */
126*77cb4d3eSLandon J. Fuller 		otype = itype;
127*77cb4d3eSLandon J. Fuller 	}
128*77cb4d3eSLandon J. Fuller 
129*77cb4d3eSLandon J. Fuller 	/* Initialize value instance */
130*77cb4d3eSLandon J. Fuller 	*value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
131*77cb4d3eSLandon J. Fuller 
132*77cb4d3eSLandon J. Fuller 	/* If input data already in native format, init directly. */
133*77cb4d3eSLandon J. Fuller 	if (otype == itype) {
134*77cb4d3eSLandon J. Fuller 		error = bhnd_nvram_val_set(value, inp, ilen, itype, flags);
135*77cb4d3eSLandon J. Fuller 		if (error)
136*77cb4d3eSLandon J. Fuller 			return (error);
137*77cb4d3eSLandon J. Fuller 
138*77cb4d3eSLandon J. Fuller 		return (0);
139*77cb4d3eSLandon J. Fuller 	}
140*77cb4d3eSLandon J. Fuller 
141*77cb4d3eSLandon J. Fuller 	/* Determine size when encoded in native format */
142*77cb4d3eSLandon J. Fuller 	error = bhnd_nvram_value_coerce(inp, ilen, itype, NULL, &olen, otype);
143*77cb4d3eSLandon J. Fuller 	if (error)
144*77cb4d3eSLandon J. Fuller 		return (error);
145*77cb4d3eSLandon J. Fuller 
146*77cb4d3eSLandon J. Fuller 	/* Fetch reference to (or allocate) an appropriately sized buffer */
147*77cb4d3eSLandon J. Fuller 	outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
148*77cb4d3eSLandon J. Fuller 	if (outp == NULL)
149*77cb4d3eSLandon J. Fuller 		return (ENOMEM);
150*77cb4d3eSLandon J. Fuller 
151*77cb4d3eSLandon J. Fuller 	/* Perform encode */
152*77cb4d3eSLandon J. Fuller 	error = bhnd_nvram_value_coerce(inp, ilen, itype, outp, &olen, otype);
153*77cb4d3eSLandon J. Fuller 	if (error)
154*77cb4d3eSLandon J. Fuller 		return (error);
155*77cb4d3eSLandon J. Fuller 
156*77cb4d3eSLandon J. Fuller 	return (0);
157*77cb4d3eSLandon J. Fuller }
158*77cb4d3eSLandon J. Fuller 
159*77cb4d3eSLandon J. Fuller /**
160*77cb4d3eSLandon J. Fuller  * Initialize an externally allocated instance of @p value with @p fmt from the
161*77cb4d3eSLandon J. Fuller  * given @p inp buffer of @p itype and @p ilen.
162*77cb4d3eSLandon J. Fuller  *
163*77cb4d3eSLandon J. Fuller  * On success, the caller owns a reference to @p value, and is responsible for
164*77cb4d3eSLandon J. Fuller  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
165*77cb4d3eSLandon J. Fuller  *
166*77cb4d3eSLandon J. Fuller  * @param	value	The externally allocated value instance to be
167*77cb4d3eSLandon J. Fuller  *			initialized.
168*77cb4d3eSLandon J. Fuller  * @param	fmt	The value's format, or NULL to use the default format
169*77cb4d3eSLandon J. Fuller  *			for @p itype.
170*77cb4d3eSLandon J. Fuller  * @param	inp	Input buffer.
171*77cb4d3eSLandon J. Fuller  * @param	ilen	Input buffer length.
172*77cb4d3eSLandon J. Fuller  * @param	itype	Input buffer type.
173*77cb4d3eSLandon J. Fuller  * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
174*77cb4d3eSLandon J. Fuller  *
175*77cb4d3eSLandon J. Fuller  * @retval 0		success
176*77cb4d3eSLandon J. Fuller  * @retval ENOMEM	If allocation fails.
177*77cb4d3eSLandon J. Fuller  * @retval EFTYPE	If @p fmt initialization from @p itype is unsupported.
178*77cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
179*77cb4d3eSLandon J. Fuller  *			@p itype.
180*77cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
181*77cb4d3eSLandon J. Fuller  *			@p fmt representation.
182*77cb4d3eSLandon J. Fuller  */
183*77cb4d3eSLandon J. Fuller int
184*77cb4d3eSLandon J. Fuller bhnd_nvram_val_init(bhnd_nvram_val_t *value, const bhnd_nvram_val_fmt_t *fmt,
185*77cb4d3eSLandon J. Fuller     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
186*77cb4d3eSLandon J. Fuller {
187*77cb4d3eSLandon J. Fuller 	int error;
188*77cb4d3eSLandon J. Fuller 
189*77cb4d3eSLandon J. Fuller 	error = bhnd_nvram_val_init_common(value, BHND_NVRAM_VAL_STORAGE_AUTO,
190*77cb4d3eSLandon J. Fuller 	    fmt, inp, ilen, itype, flags);
191*77cb4d3eSLandon J. Fuller 	if (error)
192*77cb4d3eSLandon J. Fuller 		bhnd_nvram_val_release(value);
193*77cb4d3eSLandon J. Fuller 
194*77cb4d3eSLandon J. Fuller 	return (error);
195*77cb4d3eSLandon J. Fuller }
196*77cb4d3eSLandon J. Fuller 
197*77cb4d3eSLandon J. Fuller /**
198*77cb4d3eSLandon J. Fuller  * Allocate a value instance with @p fmt, and attempt to initialize its internal
199*77cb4d3eSLandon J. Fuller  * representation from the given @p inp buffer of @p itype and @p ilen.
200*77cb4d3eSLandon J. Fuller  *
201*77cb4d3eSLandon J. Fuller  * On success, the caller owns a reference to @p value, and is responsible for
202*77cb4d3eSLandon J. Fuller  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
203*77cb4d3eSLandon J. Fuller  *
204*77cb4d3eSLandon J. Fuller  * @param[out]	value	On success, the allocated value instance.
205*77cb4d3eSLandon J. Fuller  * @param	fmt	The value's format, or NULL to use the default format
206*77cb4d3eSLandon J. Fuller  *			for @p itype.
207*77cb4d3eSLandon J. Fuller  * @param	inp	Input buffer.
208*77cb4d3eSLandon J. Fuller  * @param	ilen	Input buffer length.
209*77cb4d3eSLandon J. Fuller  * @param	itype	Input buffer type.
210*77cb4d3eSLandon J. Fuller  * @param	flags	Value flags (see BHND_NVRAM_VAL_*).
211*77cb4d3eSLandon J. Fuller  *
212*77cb4d3eSLandon J. Fuller  * @retval 0		success
213*77cb4d3eSLandon J. Fuller  * @retval ENOMEM	If allocation fails.
214*77cb4d3eSLandon J. Fuller  * @retval EFTYPE	If @p fmt initialization from @p itype is unsupported.
215*77cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
216*77cb4d3eSLandon J. Fuller  *			@p itype.
217*77cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
218*77cb4d3eSLandon J. Fuller  *			@p fmt representation.
219*77cb4d3eSLandon J. Fuller  */
220*77cb4d3eSLandon J. Fuller int
221*77cb4d3eSLandon J. Fuller bhnd_nvram_val_new(bhnd_nvram_val_t **value, const bhnd_nvram_val_fmt_t *fmt,
222*77cb4d3eSLandon J. Fuller     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
223*77cb4d3eSLandon J. Fuller {
224*77cb4d3eSLandon J. Fuller 	int error;
225*77cb4d3eSLandon J. Fuller 
226*77cb4d3eSLandon J. Fuller 	/* Allocate new instance */
227*77cb4d3eSLandon J. Fuller 	if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
228*77cb4d3eSLandon J. Fuller 		return (ENOMEM);
229*77cb4d3eSLandon J. Fuller 
230*77cb4d3eSLandon J. Fuller 	/* Perform common initialization. */
231*77cb4d3eSLandon J. Fuller 	error = bhnd_nvram_val_init_common(*value,
232*77cb4d3eSLandon J. Fuller 	    BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, inp, ilen, itype, flags);
233*77cb4d3eSLandon J. Fuller 	if (error) {
234*77cb4d3eSLandon J. Fuller 		/* Will also free() the value allocation */
235*77cb4d3eSLandon J. Fuller 		bhnd_nvram_val_release(*value);
236*77cb4d3eSLandon J. Fuller 	}
237*77cb4d3eSLandon J. Fuller 
238*77cb4d3eSLandon J. Fuller 	return (error);
239*77cb4d3eSLandon J. Fuller }
240*77cb4d3eSLandon J. Fuller 
241*77cb4d3eSLandon J. Fuller /**
242*77cb4d3eSLandon J. Fuller  * Copy or retain a reference to @p value.
243*77cb4d3eSLandon J. Fuller  *
244*77cb4d3eSLandon J. Fuller  * On success, the caller is responsible for freeing the result via
245*77cb4d3eSLandon J. Fuller  * bhnd_nvram_val_release().
246*77cb4d3eSLandon J. Fuller  *
247*77cb4d3eSLandon J. Fuller  * @param	value	The value to be copied (or retained).
248*77cb4d3eSLandon J. Fuller  *
249*77cb4d3eSLandon J. Fuller  * @retval bhnd_nvram_val_t	if @p value was successfully copied or retained.
250*77cb4d3eSLandon J. Fuller  * @retval NULL			if allocation failed.
251*77cb4d3eSLandon J. Fuller  */
252*77cb4d3eSLandon J. Fuller bhnd_nvram_val_t *
253*77cb4d3eSLandon J. Fuller bhnd_nvram_val_copy(bhnd_nvram_val_t *value)
254*77cb4d3eSLandon J. Fuller {
255*77cb4d3eSLandon J. Fuller 	bhnd_nvram_val_t	*result;
256*77cb4d3eSLandon J. Fuller 	const void		*bytes;
257*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type		 type;
258*77cb4d3eSLandon J. Fuller 	size_t			 len;
259*77cb4d3eSLandon J. Fuller 	uint32_t		 flags;
260*77cb4d3eSLandon J. Fuller 	int			 error;
261*77cb4d3eSLandon J. Fuller 
262*77cb4d3eSLandon J. Fuller 	/* If dynamically allocated, simply bump the reference count */
263*77cb4d3eSLandon J. Fuller 	if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC) {
264*77cb4d3eSLandon J. Fuller 		refcount_acquire(&value->refs);
265*77cb4d3eSLandon J. Fuller 		return (value);
266*77cb4d3eSLandon J. Fuller 	}
267*77cb4d3eSLandon J. Fuller 
268*77cb4d3eSLandon J. Fuller 	/* Otherwise, we need to perform an actual copy */
269*77cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
270*77cb4d3eSLandon J. Fuller 	    "active refcount (%u)", value->refs));
271*77cb4d3eSLandon J. Fuller 
272*77cb4d3eSLandon J. Fuller 	/* Compute the new value's flags based on the source value */
273*77cb4d3eSLandon J. Fuller 	switch (value->data_storage) {
274*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_NONE:
275*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_INLINE:
276*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_WEAK:
277*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
278*77cb4d3eSLandon J. Fuller 		/* Copy the source data and permit additional allocation if the
279*77cb4d3eSLandon J. Fuller 		 * value cannot be represented inline */
280*77cb4d3eSLandon J. Fuller 		flags = BHND_NVRAM_VAL_COPY_DATA|BHND_NVRAM_VAL_DYNAMIC;
281*77cb4d3eSLandon J. Fuller 		break;
282*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_STATIC:
283*77cb4d3eSLandon J. Fuller 		flags = BHND_NVRAM_VAL_STATIC_DATA;
284*77cb4d3eSLandon J. Fuller 		break;
285*77cb4d3eSLandon J. Fuller 	default:
286*77cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("invalid storage type: %d", value->data_storage);
287*77cb4d3eSLandon J. Fuller 	}
288*77cb4d3eSLandon J. Fuller 
289*77cb4d3eSLandon J. Fuller 	/* Allocate new value copy */
290*77cb4d3eSLandon J. Fuller 	bytes = bhnd_nvram_val_bytes(value, &len, &type);
291*77cb4d3eSLandon J. Fuller 	error = bhnd_nvram_val_new(&result, value->fmt, bytes, len, type,
292*77cb4d3eSLandon J. Fuller 	    flags);
293*77cb4d3eSLandon J. Fuller 	if (error) {
294*77cb4d3eSLandon J. Fuller 		BHND_NV_LOG("copy failed: %d", error);
295*77cb4d3eSLandon J. Fuller 		return (NULL);
296*77cb4d3eSLandon J. Fuller 	}
297*77cb4d3eSLandon J. Fuller 
298*77cb4d3eSLandon J. Fuller 	return (result);
299*77cb4d3eSLandon J. Fuller }
300*77cb4d3eSLandon J. Fuller 
301*77cb4d3eSLandon J. Fuller /**
302*77cb4d3eSLandon J. Fuller  * Release a reference to @p value.
303*77cb4d3eSLandon J. Fuller  *
304*77cb4d3eSLandon J. Fuller  * If this is the last reference, all associated resources will be freed.
305*77cb4d3eSLandon J. Fuller  *
306*77cb4d3eSLandon J. Fuller  * @param	value	The value to be released.
307*77cb4d3eSLandon J. Fuller  */
308*77cb4d3eSLandon J. Fuller void
309*77cb4d3eSLandon J. Fuller bhnd_nvram_val_release(bhnd_nvram_val_t *value)
310*77cb4d3eSLandon J. Fuller {
311*77cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
312*77cb4d3eSLandon J. Fuller 
313*77cb4d3eSLandon J. Fuller 	/* Drop reference */
314*77cb4d3eSLandon J. Fuller 	if (!refcount_release(&value->refs))
315*77cb4d3eSLandon J. Fuller 		return;
316*77cb4d3eSLandon J. Fuller 
317*77cb4d3eSLandon J. Fuller 	/* Free allocated external representation data */
318*77cb4d3eSLandon J. Fuller 	if (value->data_storage == BHND_NVRAM_VAL_DATA_EXT_ALLOC)
319*77cb4d3eSLandon J. Fuller 		bhnd_nv_free(__DECONST(void *, value->data.ptr));
320*77cb4d3eSLandon J. Fuller 
321*77cb4d3eSLandon J. Fuller 	/* Free instance if dynamically allocated */
322*77cb4d3eSLandon J. Fuller 	if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
323*77cb4d3eSLandon J. Fuller 		bhnd_nv_free(value);
324*77cb4d3eSLandon J. Fuller }
325*77cb4d3eSLandon J. Fuller 
326*77cb4d3eSLandon J. Fuller /**
327*77cb4d3eSLandon J. Fuller  * Standard string/char array/char encoding implementation.
328*77cb4d3eSLandon J. Fuller  *
329*77cb4d3eSLandon J. Fuller  * Input type must be one of:
330*77cb4d3eSLandon J. Fuller  * - BHND_NVRAM_TYPE_STRING
331*77cb4d3eSLandon J. Fuller  * - BHND_NVRAM_TYPE_CHAR
332*77cb4d3eSLandon J. Fuller  * - BHND_NVRAM_TYPE_CHAR_ARRAY
333*77cb4d3eSLandon J. Fuller  */
334*77cb4d3eSLandon J. Fuller static int
335*77cb4d3eSLandon J. Fuller bhnd_nvram_val_encode_string(void *outp, size_t *olen, bhnd_nvram_type otype,
336*77cb4d3eSLandon J. Fuller      const void *inp, size_t ilen, bhnd_nvram_type itype)
337*77cb4d3eSLandon J. Fuller {
338*77cb4d3eSLandon J. Fuller 	const char	*cstr;
339*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype_base;
340*77cb4d3eSLandon J. Fuller 	size_t		 cstr_size, cstr_len;
341*77cb4d3eSLandon J. Fuller 	size_t		 limit, nbytes;
342*77cb4d3eSLandon J. Fuller 
343*77cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(
344*77cb4d3eSLandon J. Fuller 	    itype == BHND_NVRAM_TYPE_STRING ||
345*77cb4d3eSLandon J. Fuller 	    itype == BHND_NVRAM_TYPE_CHAR ||
346*77cb4d3eSLandon J. Fuller 	    itype == BHND_NVRAM_TYPE_CHAR_ARRAY,
347*77cb4d3eSLandon J. Fuller 	    ("unsupported type: %d", itype));
348*77cb4d3eSLandon J. Fuller 
349*77cb4d3eSLandon J. Fuller 	cstr = inp;
350*77cb4d3eSLandon J. Fuller 	cstr_size = ilen;
351*77cb4d3eSLandon J. Fuller 	nbytes = 0;
352*77cb4d3eSLandon J. Fuller 	otype_base = bhnd_nvram_base_type(otype);
353*77cb4d3eSLandon J. Fuller 
354*77cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
355*77cb4d3eSLandon J. Fuller 	if (outp != NULL)
356*77cb4d3eSLandon J. Fuller 		limit = *olen;
357*77cb4d3eSLandon J. Fuller 	else
358*77cb4d3eSLandon J. Fuller 		limit = 0;
359*77cb4d3eSLandon J. Fuller 
360*77cb4d3eSLandon J. Fuller 	/* Determine string length, minus trailing NUL (if any) */
361*77cb4d3eSLandon J. Fuller 	cstr_len = strnlen(cstr, cstr_size);
362*77cb4d3eSLandon J. Fuller 
363*77cb4d3eSLandon J. Fuller 	/* Parse the field data */
364*77cb4d3eSLandon J. Fuller 	switch (otype) {
365*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
366*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
367*77cb4d3eSLandon J. Fuller 		/* String must contain exactly 1 non-terminating-NUL character
368*77cb4d3eSLandon J. Fuller 		 * to be represented as a single char */
369*77cb4d3eSLandon J. Fuller 		if (!bhnd_nvram_is_array_type(otype)) {
370*77cb4d3eSLandon J. Fuller 			if (cstr_len != 1)
371*77cb4d3eSLandon J. Fuller 				return (EFTYPE);
372*77cb4d3eSLandon J. Fuller 		}
373*77cb4d3eSLandon J. Fuller 
374*77cb4d3eSLandon J. Fuller 		/* Copy out the characters directly (excluding trailing NUL) */
375*77cb4d3eSLandon J. Fuller 		for (size_t i = 0; i < cstr_len; i++) {
376*77cb4d3eSLandon J. Fuller 			if (limit > nbytes)
377*77cb4d3eSLandon J. Fuller 				*((uint8_t *)outp + nbytes) = cstr[i];
378*77cb4d3eSLandon J. Fuller 			nbytes++;
379*77cb4d3eSLandon J. Fuller 		}
380*77cb4d3eSLandon J. Fuller 
381*77cb4d3eSLandon J. Fuller 		/* Provide required length */
382*77cb4d3eSLandon J. Fuller 		*olen = nbytes;
383*77cb4d3eSLandon J. Fuller 		if (limit < *olen && outp != NULL)
384*77cb4d3eSLandon J. Fuller 			return (ENOMEM);
385*77cb4d3eSLandon J. Fuller 
386*77cb4d3eSLandon J. Fuller 		return (0);
387*77cb4d3eSLandon J. Fuller 
388*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
389*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
390*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
391*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
392*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
393*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
394*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
395*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
396*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
397*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
398*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
399*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
400*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
401*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
402*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
403*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY: {
404*77cb4d3eSLandon J. Fuller 		const char	*p;
405*77cb4d3eSLandon J. Fuller 		size_t		 plen, parsed_len;
406*77cb4d3eSLandon J. Fuller 		int		 error;
407*77cb4d3eSLandon J. Fuller 
408*77cb4d3eSLandon J. Fuller 		/* Trim leading/trailing whitespace */
409*77cb4d3eSLandon J. Fuller 		p = cstr;
410*77cb4d3eSLandon J. Fuller 		plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
411*77cb4d3eSLandon J. Fuller 
412*77cb4d3eSLandon J. Fuller 		/* Try to parse the integer value */
413*77cb4d3eSLandon J. Fuller 		error = bhnd_nvram_parse_int(p, plen, 0, &parsed_len, outp,
414*77cb4d3eSLandon J. Fuller 		    olen, otype_base);
415*77cb4d3eSLandon J. Fuller 		if (error) {
416*77cb4d3eSLandon J. Fuller 			BHND_NV_DEBUG("error parsing '%.*s' as integer: %d\n",
417*77cb4d3eSLandon J. Fuller 			    BHND_NV_PRINT_WIDTH(plen), p, error);
418*77cb4d3eSLandon J. Fuller 			return (error);
419*77cb4d3eSLandon J. Fuller 		}
420*77cb4d3eSLandon J. Fuller 
421*77cb4d3eSLandon J. Fuller 		/* Do additional bytes remain unparsed? */
422*77cb4d3eSLandon J. Fuller 		if (plen != parsed_len) {
423*77cb4d3eSLandon J. Fuller 			BHND_NV_DEBUG("error parsing '%.*s' as a single "
424*77cb4d3eSLandon J. Fuller 			    "integer value; trailing garbage '%.*s'\n",
425*77cb4d3eSLandon J. Fuller 			    BHND_NV_PRINT_WIDTH(plen), p,
426*77cb4d3eSLandon J. Fuller 			    BHND_NV_PRINT_WIDTH(plen-parsed_len), p+parsed_len);
427*77cb4d3eSLandon J. Fuller 			return (EFTYPE);
428*77cb4d3eSLandon J. Fuller 		}
429*77cb4d3eSLandon J. Fuller 
430*77cb4d3eSLandon J. Fuller 		return (0);
431*77cb4d3eSLandon J. Fuller 	}
432*77cb4d3eSLandon J. Fuller 
433*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
434*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
435*77cb4d3eSLandon J. Fuller 		/* Copy out the string representation as-is */
436*77cb4d3eSLandon J. Fuller 		*olen = cstr_size;
437*77cb4d3eSLandon J. Fuller 
438*77cb4d3eSLandon J. Fuller 		/* Need additional space for trailing NUL? */
439*77cb4d3eSLandon J. Fuller 		if (cstr_len == cstr_size)
440*77cb4d3eSLandon J. Fuller 			(*olen)++;
441*77cb4d3eSLandon J. Fuller 
442*77cb4d3eSLandon J. Fuller 		/* Skip output? */
443*77cb4d3eSLandon J. Fuller 		if (outp == NULL)
444*77cb4d3eSLandon J. Fuller 			return (0);
445*77cb4d3eSLandon J. Fuller 
446*77cb4d3eSLandon J. Fuller 		/* Verify required length */
447*77cb4d3eSLandon J. Fuller 		if (limit < *olen)
448*77cb4d3eSLandon J. Fuller 			return (ENOMEM);
449*77cb4d3eSLandon J. Fuller 
450*77cb4d3eSLandon J. Fuller 		/* Copy and NUL terminate */
451*77cb4d3eSLandon J. Fuller 		strncpy(outp, cstr, cstr_len);
452*77cb4d3eSLandon J. Fuller 		*((char *)outp + cstr_len) = '\0';
453*77cb4d3eSLandon J. Fuller 
454*77cb4d3eSLandon J. Fuller 		return (0);
455*77cb4d3eSLandon J. Fuller 	}
456*77cb4d3eSLandon J. Fuller 
457*77cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("unknown type %s", bhnd_nvram_type_name(otype));
458*77cb4d3eSLandon J. Fuller }
459*77cb4d3eSLandon J. Fuller 
460*77cb4d3eSLandon J. Fuller /**
461*77cb4d3eSLandon J. Fuller  * Standard integer encoding implementation.
462*77cb4d3eSLandon J. Fuller  */
463*77cb4d3eSLandon J. Fuller static int
464*77cb4d3eSLandon J. Fuller bhnd_nvram_val_encode_int(void *outp, size_t *olen, bhnd_nvram_type otype,
465*77cb4d3eSLandon J. Fuller      const void *inp, size_t ilen, bhnd_nvram_type itype)
466*77cb4d3eSLandon J. Fuller {
467*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype_base;
468*77cb4d3eSLandon J. Fuller 	size_t		 limit, nbytes;
469*77cb4d3eSLandon J. Fuller 	bool		 itype_signed, otype_signed, otype_int;
470*77cb4d3eSLandon J. Fuller 	union {
471*77cb4d3eSLandon J. Fuller 		uint64_t	u64;
472*77cb4d3eSLandon J. Fuller 		int64_t		i64;
473*77cb4d3eSLandon J. Fuller 	} intv;
474*77cb4d3eSLandon J. Fuller 
475*77cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("non-integer type"));
476*77cb4d3eSLandon J. Fuller 
477*77cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
478*77cb4d3eSLandon J. Fuller 	if (outp != NULL)
479*77cb4d3eSLandon J. Fuller 		limit = *olen;
480*77cb4d3eSLandon J. Fuller 	else
481*77cb4d3eSLandon J. Fuller 		limit = 0;
482*77cb4d3eSLandon J. Fuller 
483*77cb4d3eSLandon J. Fuller 	/* Fetch output type info */
484*77cb4d3eSLandon J. Fuller 	otype_base = bhnd_nvram_base_type(otype);
485*77cb4d3eSLandon J. Fuller 	otype_int = bhnd_nvram_is_int_type(otype);
486*77cb4d3eSLandon J. Fuller 	otype_signed = bhnd_nvram_is_signed_type(otype_base);
487*77cb4d3eSLandon J. Fuller 
488*77cb4d3eSLandon J. Fuller 	/*
489*77cb4d3eSLandon J. Fuller 	 * Promote integer value to a common 64-bit representation.
490*77cb4d3eSLandon J. Fuller 	 */
491*77cb4d3eSLandon J. Fuller 	switch (itype) {
492*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
493*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint8_t))
494*77cb4d3eSLandon J. Fuller 			return (EFAULT);
495*77cb4d3eSLandon J. Fuller 
496*77cb4d3eSLandon J. Fuller 		itype_signed = false;
497*77cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint8_t *)inp;
498*77cb4d3eSLandon J. Fuller 		break;
499*77cb4d3eSLandon J. Fuller 
500*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
501*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint16_t))
502*77cb4d3eSLandon J. Fuller 			return (EFAULT);
503*77cb4d3eSLandon J. Fuller 
504*77cb4d3eSLandon J. Fuller 		itype_signed = false;
505*77cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint16_t *)inp;
506*77cb4d3eSLandon J. Fuller 		break;
507*77cb4d3eSLandon J. Fuller 
508*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
509*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint32_t))
510*77cb4d3eSLandon J. Fuller 			return (EFAULT);
511*77cb4d3eSLandon J. Fuller 
512*77cb4d3eSLandon J. Fuller 		itype_signed = false;
513*77cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint32_t *)inp;
514*77cb4d3eSLandon J. Fuller 		break;
515*77cb4d3eSLandon J. Fuller 
516*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
517*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(uint64_t))
518*77cb4d3eSLandon J. Fuller 			return (EFAULT);
519*77cb4d3eSLandon J. Fuller 
520*77cb4d3eSLandon J. Fuller 		itype_signed = false;
521*77cb4d3eSLandon J. Fuller 		intv.u64 = *(const uint64_t *)inp;
522*77cb4d3eSLandon J. Fuller 		break;
523*77cb4d3eSLandon J. Fuller 
524*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
525*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int8_t))
526*77cb4d3eSLandon J. Fuller 			return (EFAULT);
527*77cb4d3eSLandon J. Fuller 
528*77cb4d3eSLandon J. Fuller 		itype_signed = true;
529*77cb4d3eSLandon J. Fuller 		intv.i64 = *(const int8_t *)inp;
530*77cb4d3eSLandon J. Fuller 		break;
531*77cb4d3eSLandon J. Fuller 
532*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
533*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int16_t))
534*77cb4d3eSLandon J. Fuller 			return (EFAULT);
535*77cb4d3eSLandon J. Fuller 
536*77cb4d3eSLandon J. Fuller 		itype_signed = true;
537*77cb4d3eSLandon J. Fuller 		intv.i64 = *(const int16_t *)inp;
538*77cb4d3eSLandon J. Fuller 		break;
539*77cb4d3eSLandon J. Fuller 
540*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
541*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int32_t))
542*77cb4d3eSLandon J. Fuller 			return (EFAULT);
543*77cb4d3eSLandon J. Fuller 
544*77cb4d3eSLandon J. Fuller 		itype_signed = true;
545*77cb4d3eSLandon J. Fuller 		intv.i64 = *(const int32_t *)inp;
546*77cb4d3eSLandon J. Fuller 		break;
547*77cb4d3eSLandon J. Fuller 
548*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
549*77cb4d3eSLandon J. Fuller 		if (ilen != sizeof(int32_t))
550*77cb4d3eSLandon J. Fuller 			return (EFAULT);
551*77cb4d3eSLandon J. Fuller 
552*77cb4d3eSLandon J. Fuller 		itype_signed = true;
553*77cb4d3eSLandon J. Fuller 		intv.i64 = *(const int32_t *)inp;
554*77cb4d3eSLandon J. Fuller 		break;
555*77cb4d3eSLandon J. Fuller 
556*77cb4d3eSLandon J. Fuller 	default:
557*77cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("invalid type %d\n", itype);
558*77cb4d3eSLandon J. Fuller 	}
559*77cb4d3eSLandon J. Fuller 
560*77cb4d3eSLandon J. Fuller 	/* Perform signed/unsigned conversion */
561*77cb4d3eSLandon J. Fuller 	if (itype_signed && otype_int && !otype_signed) {
562*77cb4d3eSLandon J. Fuller 		if (intv.i64 < 0) {
563*77cb4d3eSLandon J. Fuller 			/* Can't represent negative value */
564*77cb4d3eSLandon J. Fuller 			BHND_NV_LOG("cannot represent %" PRId64 " as %s\n",
565*77cb4d3eSLandon J. Fuller 			    intv.i64, bhnd_nvram_type_name(otype));
566*77cb4d3eSLandon J. Fuller 
567*77cb4d3eSLandon J. Fuller 			return (ERANGE);
568*77cb4d3eSLandon J. Fuller 		}
569*77cb4d3eSLandon J. Fuller 
570*77cb4d3eSLandon J. Fuller 		/* Convert to unsigned representation */
571*77cb4d3eSLandon J. Fuller 		intv.u64 = intv.i64;
572*77cb4d3eSLandon J. Fuller 
573*77cb4d3eSLandon J. Fuller 	} else if (!itype_signed && otype_int && otype_signed) {
574*77cb4d3eSLandon J. Fuller 		/* Handle unsigned -> signed coercions */
575*77cb4d3eSLandon J. Fuller 		if (intv.u64 > INT64_MAX) {
576*77cb4d3eSLandon J. Fuller 			/* Can't represent positive value */
577*77cb4d3eSLandon J. Fuller 			BHND_NV_LOG("cannot represent %" PRIu64 " as %s\n",
578*77cb4d3eSLandon J. Fuller 			    intv.u64, bhnd_nvram_type_name(otype));
579*77cb4d3eSLandon J. Fuller 			return (ERANGE);
580*77cb4d3eSLandon J. Fuller 		}
581*77cb4d3eSLandon J. Fuller 
582*77cb4d3eSLandon J. Fuller 		/* Convert to signed representation */
583*77cb4d3eSLandon J. Fuller 		intv.i64 = intv.u64;
584*77cb4d3eSLandon J. Fuller 	}
585*77cb4d3eSLandon J. Fuller 
586*77cb4d3eSLandon J. Fuller 	/* Write output */
587*77cb4d3eSLandon J. Fuller 	switch (otype) {
588*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
589*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
590*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
591*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
592*77cb4d3eSLandon J. Fuller 		if (intv.u64 > UINT8_MAX)
593*77cb4d3eSLandon J. Fuller 			return (ERANGE);
594*77cb4d3eSLandon J. Fuller 
595*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint8_t);
596*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
597*77cb4d3eSLandon J. Fuller 			*((uint8_t *)outp) = (uint8_t)intv.u64;
598*77cb4d3eSLandon J. Fuller 		break;
599*77cb4d3eSLandon J. Fuller 
600*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
601*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
602*77cb4d3eSLandon J. Fuller 		if (intv.u64 > UINT16_MAX)
603*77cb4d3eSLandon J. Fuller 			return (ERANGE);
604*77cb4d3eSLandon J. Fuller 
605*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint16_t);
606*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
607*77cb4d3eSLandon J. Fuller 			*((uint16_t *)outp) = (uint16_t)intv.u64;
608*77cb4d3eSLandon J. Fuller 		break;
609*77cb4d3eSLandon J. Fuller 
610*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
611*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
612*77cb4d3eSLandon J. Fuller 		if (intv.u64 > UINT32_MAX)
613*77cb4d3eSLandon J. Fuller 			return (ERANGE);
614*77cb4d3eSLandon J. Fuller 
615*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint32_t);
616*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
617*77cb4d3eSLandon J. Fuller 			*((uint32_t *)outp) = (uint32_t)intv.u64;
618*77cb4d3eSLandon J. Fuller 		break;
619*77cb4d3eSLandon J. Fuller 
620*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
621*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
622*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(uint64_t);
623*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
624*77cb4d3eSLandon J. Fuller 			*((uint64_t *)outp) = intv.u64;
625*77cb4d3eSLandon J. Fuller 		break;
626*77cb4d3eSLandon J. Fuller 
627*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
628*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
629*77cb4d3eSLandon J. Fuller 		if (intv.i64 < INT8_MIN || intv.i64 > INT8_MAX)
630*77cb4d3eSLandon J. Fuller 			return (ERANGE);
631*77cb4d3eSLandon J. Fuller 
632*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(int8_t);
633*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
634*77cb4d3eSLandon J. Fuller 			*((int8_t *)outp) = (int8_t)intv.i64;
635*77cb4d3eSLandon J. Fuller 		break;
636*77cb4d3eSLandon J. Fuller 
637*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
638*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
639*77cb4d3eSLandon J. Fuller 		if (intv.i64 < INT16_MIN || intv.i64 > INT16_MAX)
640*77cb4d3eSLandon J. Fuller 			return (ERANGE);
641*77cb4d3eSLandon J. Fuller 
642*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(int16_t);
643*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
644*77cb4d3eSLandon J. Fuller 			*((int16_t *)outp) = (int16_t)intv.i64;
645*77cb4d3eSLandon J. Fuller 		break;
646*77cb4d3eSLandon J. Fuller 
647*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
648*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
649*77cb4d3eSLandon J. Fuller 		if (intv.i64 < INT32_MIN || intv.i64 > INT32_MAX)
650*77cb4d3eSLandon J. Fuller 			return (ERANGE);
651*77cb4d3eSLandon J. Fuller 
652*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(int32_t);
653*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
654*77cb4d3eSLandon J. Fuller 			*((int32_t *)outp) = (int32_t)intv.i64;
655*77cb4d3eSLandon J. Fuller 		break;
656*77cb4d3eSLandon J. Fuller 
657*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
658*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
659*77cb4d3eSLandon J. Fuller 		nbytes = sizeof(int64_t);
660*77cb4d3eSLandon J. Fuller 		if (limit >= nbytes)
661*77cb4d3eSLandon J. Fuller 			*((int64_t *)outp) = intv.i64;
662*77cb4d3eSLandon J. Fuller 		break;
663*77cb4d3eSLandon J. Fuller 
664*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
665*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY: {
666*77cb4d3eSLandon J. Fuller 		ssize_t len;
667*77cb4d3eSLandon J. Fuller 
668*77cb4d3eSLandon J. Fuller 		/* Attempt to write the entry + NUL */
669*77cb4d3eSLandon J. Fuller 		if (otype_signed) {
670*77cb4d3eSLandon J. Fuller 			len = snprintf(outp, limit, "%" PRId64, intv.i64);
671*77cb4d3eSLandon J. Fuller 		} else {
672*77cb4d3eSLandon J. Fuller 			len = snprintf(outp, limit, "%" PRIu64, intv.u64);
673*77cb4d3eSLandon J. Fuller 		}
674*77cb4d3eSLandon J. Fuller 
675*77cb4d3eSLandon J. Fuller 		if (len < 0) {
676*77cb4d3eSLandon J. Fuller 			BHND_NV_LOG("snprintf() failed: %zd\n", len);
677*77cb4d3eSLandon J. Fuller 			return (EFTYPE);
678*77cb4d3eSLandon J. Fuller 		}
679*77cb4d3eSLandon J. Fuller 
680*77cb4d3eSLandon J. Fuller 		/* Set total length to the formatted string length, plus
681*77cb4d3eSLandon J. Fuller 		 * trailing NUL */
682*77cb4d3eSLandon J. Fuller 		nbytes = len + 1;
683*77cb4d3eSLandon J. Fuller 		break;
684*77cb4d3eSLandon J. Fuller 	}
685*77cb4d3eSLandon J. Fuller 
686*77cb4d3eSLandon J. Fuller 	default:
687*77cb4d3eSLandon J. Fuller 		BHND_NV_LOG("unknown type %s\n", bhnd_nvram_type_name(otype));
688*77cb4d3eSLandon J. Fuller 		return (EFTYPE);
689*77cb4d3eSLandon J. Fuller 	}
690*77cb4d3eSLandon J. Fuller 
691*77cb4d3eSLandon J. Fuller 	/* Provide required length */
692*77cb4d3eSLandon J. Fuller 	*olen = nbytes;
693*77cb4d3eSLandon J. Fuller 	if (limit < *olen) {
694*77cb4d3eSLandon J. Fuller 		if (outp == NULL)
695*77cb4d3eSLandon J. Fuller 			return (0);
696*77cb4d3eSLandon J. Fuller 
697*77cb4d3eSLandon J. Fuller 		return (ENOMEM);
698*77cb4d3eSLandon J. Fuller 	}
699*77cb4d3eSLandon J. Fuller 
700*77cb4d3eSLandon J. Fuller 	return (0);
701*77cb4d3eSLandon J. Fuller }
702*77cb4d3eSLandon J. Fuller 
703*77cb4d3eSLandon J. Fuller /**
704*77cb4d3eSLandon J. Fuller  * Encode the given @p value as @p otype, writing the result to @p outp.
705*77cb4d3eSLandon J. Fuller  *
706*77cb4d3eSLandon J. Fuller  * @param		value	The value to be encoded.
707*77cb4d3eSLandon J. Fuller  * @param[out]		outp	On success, the value will be written to this
708*77cb4d3eSLandon J. Fuller  *				buffer. This argment may be NULL if the value is
709*77cb4d3eSLandon J. Fuller  *				not desired.
710*77cb4d3eSLandon J. Fuller  * @param[in,out]	olen	The capacity of @p outp. On success, will be set
711*77cb4d3eSLandon J. Fuller  *				to the actual size of the requested value.
712*77cb4d3eSLandon J. Fuller  * @param		otype	The data type to be written to @p outp.
713*77cb4d3eSLandon J. Fuller  *
714*77cb4d3eSLandon J. Fuller  * @retval 0		success
715*77cb4d3eSLandon J. Fuller  * @retval ENOMEM	If the @p outp is non-NULL, and the provided @p olen
716*77cb4d3eSLandon J. Fuller  *			is too small to hold the encoded value.
717*77cb4d3eSLandon J. Fuller  * @retval EFTYPE	If value coercion from @p value to @p otype is
718*77cb4d3eSLandon J. Fuller  *			impossible.
719*77cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
720*77cb4d3eSLandon J. Fuller  *			a @p otype representation.
721*77cb4d3eSLandon J. Fuller  */
722*77cb4d3eSLandon J. Fuller int
723*77cb4d3eSLandon J. Fuller bhnd_nvram_val_encode(bhnd_nvram_val_t *value, void *outp, size_t *olen,
724*77cb4d3eSLandon J. Fuller     bhnd_nvram_type otype)
725*77cb4d3eSLandon J. Fuller {
726*77cb4d3eSLandon J. Fuller 	/* Prefer format implementation */
727*77cb4d3eSLandon J. Fuller 	if (value->fmt != NULL && value->fmt->op_encode != NULL)
728*77cb4d3eSLandon J. Fuller 		return (value->fmt->op_encode(value, outp, olen, otype));
729*77cb4d3eSLandon J. Fuller 
730*77cb4d3eSLandon J. Fuller 	return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
731*77cb4d3eSLandon J. Fuller }
732*77cb4d3eSLandon J. Fuller 
733*77cb4d3eSLandon J. Fuller /**
734*77cb4d3eSLandon J. Fuller  * Encode the given @p value's element as @p otype, writing the result to
735*77cb4d3eSLandon J. Fuller  * @p outp.
736*77cb4d3eSLandon J. Fuller  *
737*77cb4d3eSLandon J. Fuller  * @param		inp	The element to be be encoded. Must be a value
738*77cb4d3eSLandon J. Fuller  *				previously returned by bhnd_nvram_val_next()
739*77cb4d3eSLandon J. Fuller  *				or bhnd_nvram_val_elem().
740*77cb4d3eSLandon J. Fuller  * @param		ilen	The size of @p inp, as returned by
741*77cb4d3eSLandon J. Fuller  *				bhnd_nvram_val_next() or bhnd_nvram_val_elem().
742*77cb4d3eSLandon J. Fuller  * @param[out]		outp	On success, the value will be written to this
743*77cb4d3eSLandon J. Fuller  *				buffer. This argment may be NULL if the value is
744*77cb4d3eSLandon J. Fuller  *				not desired.
745*77cb4d3eSLandon J. Fuller  * @param[in,out]	olen	The capacity of @p outp. On success, will be set
746*77cb4d3eSLandon J. Fuller  *				to the actual size of the requested value.
747*77cb4d3eSLandon J. Fuller  * @param		otype	The data type to be written to @p outp.
748*77cb4d3eSLandon J. Fuller  *
749*77cb4d3eSLandon J. Fuller  * @retval 0		success
750*77cb4d3eSLandon J. Fuller  * @retval ENOMEM	If the @p outp is non-NULL, and the provided @p olen
751*77cb4d3eSLandon J. Fuller  *			is too small to hold the encoded value.
752*77cb4d3eSLandon J. Fuller  * @retval EFTYPE	If value coercion from @p value to @p otype is
753*77cb4d3eSLandon J. Fuller  *			impossible.
754*77cb4d3eSLandon J. Fuller  * @retval ERANGE	If value coercion would overflow (or underflow) the
755*77cb4d3eSLandon J. Fuller  *			a @p otype representation.
756*77cb4d3eSLandon J. Fuller  */
757*77cb4d3eSLandon J. Fuller int
758*77cb4d3eSLandon J. Fuller bhnd_nvram_val_encode_elem(bhnd_nvram_val_t *value, const void *inp,
759*77cb4d3eSLandon J. Fuller     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
760*77cb4d3eSLandon J. Fuller {
761*77cb4d3eSLandon J. Fuller 	/* Prefer format implementation */
762*77cb4d3eSLandon J. Fuller 	if (value->fmt != NULL && value->fmt->op_encode_elem != NULL) {
763*77cb4d3eSLandon J. Fuller 		return (value->fmt->op_encode_elem(value, inp, ilen, outp,
764*77cb4d3eSLandon J. Fuller 		    olen, otype));
765*77cb4d3eSLandon J. Fuller 	}
766*77cb4d3eSLandon J. Fuller 
767*77cb4d3eSLandon J. Fuller 	return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen, outp,
768*77cb4d3eSLandon J. Fuller 	    olen, otype));
769*77cb4d3eSLandon J. Fuller }
770*77cb4d3eSLandon J. Fuller 
771*77cb4d3eSLandon J. Fuller /**
772*77cb4d3eSLandon J. Fuller  * Return the type, size, and a pointer to the internal representation
773*77cb4d3eSLandon J. Fuller  * of @p value.
774*77cb4d3eSLandon J. Fuller  *
775*77cb4d3eSLandon J. Fuller  * @param	value	The value to be queried.
776*77cb4d3eSLandon J. Fuller  * @param[out]	olen	Size of the returned data, in bytes.
777*77cb4d3eSLandon J. Fuller  * @param[out]	otype	Data type.
778*77cb4d3eSLandon J. Fuller  */
779*77cb4d3eSLandon J. Fuller const void *
780*77cb4d3eSLandon J. Fuller bhnd_nvram_val_bytes(bhnd_nvram_val_t *value, size_t *olen,
781*77cb4d3eSLandon J. Fuller     bhnd_nvram_type *otype)
782*77cb4d3eSLandon J. Fuller {
783*77cb4d3eSLandon J. Fuller 	/* Provide type and length */
784*77cb4d3eSLandon J. Fuller 	*otype = value->data_type;
785*77cb4d3eSLandon J. Fuller 	*olen = value->data_len;
786*77cb4d3eSLandon J. Fuller 
787*77cb4d3eSLandon J. Fuller 	switch (value->data_storage) {
788*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
789*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_STATIC:
790*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_EXT_WEAK:
791*77cb4d3eSLandon J. Fuller 		/* Return a pointer to external storage */
792*77cb4d3eSLandon J. Fuller 		return (value->data.ptr);
793*77cb4d3eSLandon J. Fuller 
794*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_INLINE:
795*77cb4d3eSLandon J. Fuller 		/* Return a pointer to inline storage */
796*77cb4d3eSLandon J. Fuller 		return (&value->data);
797*77cb4d3eSLandon J. Fuller 
798*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_VAL_DATA_NONE:
799*77cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("uninitialized value");
800*77cb4d3eSLandon J. Fuller 	}
801*77cb4d3eSLandon J. Fuller 
802*77cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("unknown storage type: %d", value->data_storage);
803*77cb4d3eSLandon J. Fuller }
804*77cb4d3eSLandon J. Fuller 
805*77cb4d3eSLandon J. Fuller /**
806*77cb4d3eSLandon J. Fuller  * Iterate over all array elements in @p value.
807*77cb4d3eSLandon J. Fuller  *
808*77cb4d3eSLandon J. Fuller  * @param		value	The value to be iterated
809*77cb4d3eSLandon J. Fuller  * @param		prev	A value pointer previously returned by
810*77cb4d3eSLandon J. Fuller  *				bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
811*77cb4d3eSLandon J. Fuller  *				or NULL to begin iteration at the first element.
812*77cb4d3eSLandon J. Fuller  * @param[in,out]	len	If prev is non-NULL, len must be a pointer
813*77cb4d3eSLandon J. Fuller  *				to the length previously returned by
814*77cb4d3eSLandon J. Fuller  *				bhnd_nvram_val_next() or bhnd_nvram_val_elem().
815*77cb4d3eSLandon J. Fuller  *				On success, will be set to the next element's
816*77cb4d3eSLandon J. Fuller  *				length, in bytes.
817*77cb4d3eSLandon J. Fuller  *
818*77cb4d3eSLandon J. Fuller  * @retval non-NULL	A borrowed reference to the element data.
819*77cb4d3eSLandon J. Fuller  * @retval NULL		If the end of the element array is reached.
820*77cb4d3eSLandon J. Fuller  */
821*77cb4d3eSLandon J. Fuller const void *
822*77cb4d3eSLandon J. Fuller bhnd_nvram_val_next(bhnd_nvram_val_t *value, const void *prev, size_t *len)
823*77cb4d3eSLandon J. Fuller {
824*77cb4d3eSLandon J. Fuller 	/* Prefer the format implementation */
825*77cb4d3eSLandon J. Fuller 	if (value->fmt != NULL && value->fmt->op_next != NULL)
826*77cb4d3eSLandon J. Fuller 		return (value->fmt->op_next(value, prev, len));
827*77cb4d3eSLandon J. Fuller 
828*77cb4d3eSLandon J. Fuller 	return (bhnd_nvram_val_generic_next(value, prev, len));
829*77cb4d3eSLandon J. Fuller }
830*77cb4d3eSLandon J. Fuller 
831*77cb4d3eSLandon J. Fuller /**
832*77cb4d3eSLandon J. Fuller  * Return value's element data type.
833*77cb4d3eSLandon J. Fuller  *
834*77cb4d3eSLandon J. Fuller  * @param	value	The value to be queried.
835*77cb4d3eSLandon J. Fuller  */
836*77cb4d3eSLandon J. Fuller bhnd_nvram_type
837*77cb4d3eSLandon J. Fuller bhnd_nvram_val_elem_type(bhnd_nvram_val_t *value)
838*77cb4d3eSLandon J. Fuller {
839*77cb4d3eSLandon J. Fuller 	return (bhnd_nvram_base_type(value->data_type));
840*77cb4d3eSLandon J. Fuller }
841*77cb4d3eSLandon J. Fuller 
842*77cb4d3eSLandon J. Fuller /**
843*77cb4d3eSLandon J. Fuller  * Return the total number of elements represented by @p value.
844*77cb4d3eSLandon J. Fuller  */
845*77cb4d3eSLandon J. Fuller size_t
846*77cb4d3eSLandon J. Fuller bhnd_nvram_val_nelem(bhnd_nvram_val_t *value)
847*77cb4d3eSLandon J. Fuller {
848*77cb4d3eSLandon J. Fuller 	const void	*bytes;
849*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 type;
850*77cb4d3eSLandon J. Fuller 	size_t		 nelem, len;
851*77cb4d3eSLandon J. Fuller 	int		 error;
852*77cb4d3eSLandon J. Fuller 
853*77cb4d3eSLandon J. Fuller 	/* Prefer format implementation */
854*77cb4d3eSLandon J. Fuller 	if (value->fmt != NULL && value->fmt->op_nelem != NULL)
855*77cb4d3eSLandon J. Fuller 		return (value->fmt->op_nelem(value));
856*77cb4d3eSLandon J. Fuller 
857*77cb4d3eSLandon J. Fuller 	/*
858*77cb4d3eSLandon J. Fuller 	 * If a custom op_next() is defined, bhnd_nvram_value_nelem() almost
859*77cb4d3eSLandon J. Fuller 	 * certainly cannot produce a valid element count; it assumes a standard
860*77cb4d3eSLandon J. Fuller 	 * data format that may not apply when custom iteration is required.
861*77cb4d3eSLandon J. Fuller 	 *
862*77cb4d3eSLandon J. Fuller 	 * Instead, use bhnd_nvram_val_next() to parse the backing data and
863*77cb4d3eSLandon J. Fuller 	 * produce a total count.
864*77cb4d3eSLandon J. Fuller 	 */
865*77cb4d3eSLandon J. Fuller 	if (value->fmt != NULL && value->fmt->op_next != NULL) {
866*77cb4d3eSLandon J. Fuller 		const void *next;
867*77cb4d3eSLandon J. Fuller 
868*77cb4d3eSLandon J. Fuller 		next = NULL;
869*77cb4d3eSLandon J. Fuller 		nelem = 0;
870*77cb4d3eSLandon J. Fuller 		while ((next = bhnd_nvram_val_next(value, next, &len)) != NULL)
871*77cb4d3eSLandon J. Fuller 			nelem++;
872*77cb4d3eSLandon J. Fuller 
873*77cb4d3eSLandon J. Fuller 		return (nelem);
874*77cb4d3eSLandon J. Fuller 	}
875*77cb4d3eSLandon J. Fuller 
876*77cb4d3eSLandon J. Fuller 	/* Otherwise, compute the standard element count */
877*77cb4d3eSLandon J. Fuller 	bytes = bhnd_nvram_val_bytes(value, &len, &type);
878*77cb4d3eSLandon J. Fuller 	if ((error = bhnd_nvram_value_nelem(type, bytes, len, &nelem))) {
879*77cb4d3eSLandon J. Fuller 		/* Should always succeed */
880*77cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("error calculating element count for type '%s' "
881*77cb4d3eSLandon J. Fuller 		    "with length %zu: %d\n", bhnd_nvram_type_name(type), len,
882*77cb4d3eSLandon J. Fuller 		    error);
883*77cb4d3eSLandon J. Fuller 	}
884*77cb4d3eSLandon J. Fuller 
885*77cb4d3eSLandon J. Fuller 	return (nelem);
886*77cb4d3eSLandon J. Fuller }
887*77cb4d3eSLandon J. Fuller 
888*77cb4d3eSLandon J. Fuller /**
889*77cb4d3eSLandon J. Fuller  * Generic implementation of bhnd_nvram_val_op_encode(), compatible with
890*77cb4d3eSLandon J. Fuller  * all supported NVRAM data types.
891*77cb4d3eSLandon J. Fuller  */
892*77cb4d3eSLandon J. Fuller int
893*77cb4d3eSLandon J. Fuller bhnd_nvram_val_generic_encode(bhnd_nvram_val_t *value, void *outp, size_t *olen,
894*77cb4d3eSLandon J. Fuller     bhnd_nvram_type otype)
895*77cb4d3eSLandon J. Fuller {
896*77cb4d3eSLandon J. Fuller 	const void	*inp;
897*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 itype;
898*77cb4d3eSLandon J. Fuller 	size_t		 ilen;
899*77cb4d3eSLandon J. Fuller 	const void	*next;
900*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 otype_base;
901*77cb4d3eSLandon J. Fuller 	size_t		 limit, nelem, nbytes;
902*77cb4d3eSLandon J. Fuller 	size_t		 next_len;
903*77cb4d3eSLandon J. Fuller 	int		 error;
904*77cb4d3eSLandon J. Fuller 
905*77cb4d3eSLandon J. Fuller 	nbytes = 0;
906*77cb4d3eSLandon J. Fuller 	nelem = 0;
907*77cb4d3eSLandon J. Fuller 	otype_base = bhnd_nvram_base_type(otype);
908*77cb4d3eSLandon J. Fuller 
909*77cb4d3eSLandon J. Fuller 	/*
910*77cb4d3eSLandon J. Fuller 	 * Normally, a rank polymorphic type like a character array would not
911*77cb4d3eSLandon J. Fuller 	 * be representable as a rank 1 type.
912*77cb4d3eSLandon J. Fuller 	 *
913*77cb4d3eSLandon J. Fuller 	 * As a special-cased exception, we can support conversion directly
914*77cb4d3eSLandon J. Fuller 	 * from CHAR_ARRAY to STRING by treating the character array as a
915*77cb4d3eSLandon J. Fuller 	 * non-NUL-terminated string.
916*77cb4d3eSLandon J. Fuller 	 *
917*77cb4d3eSLandon J. Fuller 	 * This conversion is isomorphic; we also support conversion directly
918*77cb4d3eSLandon J. Fuller 	 * from a STRING to a CHAR_ARRAY by the same mechanism.
919*77cb4d3eSLandon J. Fuller 	 */
920*77cb4d3eSLandon J. Fuller 	inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
921*77cb4d3eSLandon J. Fuller 	if ((itype == BHND_NVRAM_TYPE_CHAR_ARRAY &&
922*77cb4d3eSLandon J. Fuller 	     otype == BHND_NVRAM_TYPE_STRING) ||
923*77cb4d3eSLandon J. Fuller 	    (itype == BHND_NVRAM_TYPE_STRING &&
924*77cb4d3eSLandon J. Fuller 	     otype == BHND_NVRAM_TYPE_CHAR_ARRAY))
925*77cb4d3eSLandon J. Fuller 	{
926*77cb4d3eSLandon J. Fuller 		return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
927*77cb4d3eSLandon J. Fuller 		    otype));
928*77cb4d3eSLandon J. Fuller 	}
929*77cb4d3eSLandon J. Fuller 
930*77cb4d3eSLandon J. Fuller 	/*
931*77cb4d3eSLandon J. Fuller 	 * If both input and output are non-array types, try to encode them
932*77cb4d3eSLandon J. Fuller 	 * without performing element iteration.
933*77cb4d3eSLandon J. Fuller 	 */
934*77cb4d3eSLandon J. Fuller 	if (!bhnd_nvram_is_array_type(itype) &&
935*77cb4d3eSLandon J. Fuller 	    !bhnd_nvram_is_array_type(otype))
936*77cb4d3eSLandon J. Fuller 	{
937*77cb4d3eSLandon J. Fuller 		return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
938*77cb4d3eSLandon J. Fuller 		    otype));
939*77cb4d3eSLandon J. Fuller 	}
940*77cb4d3eSLandon J. Fuller 
941*77cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
942*77cb4d3eSLandon J. Fuller 	if (outp != NULL)
943*77cb4d3eSLandon J. Fuller 		limit = *olen;
944*77cb4d3eSLandon J. Fuller 	else
945*77cb4d3eSLandon J. Fuller 		limit = 0;
946*77cb4d3eSLandon J. Fuller 
947*77cb4d3eSLandon J. Fuller 	/* Iterate over our array elements and encode as the requested
948*77cb4d3eSLandon J. Fuller 	 * type */
949*77cb4d3eSLandon J. Fuller 	next = NULL;
950*77cb4d3eSLandon J. Fuller 	while ((next = bhnd_nvram_val_next(value, next, &next_len))) {
951*77cb4d3eSLandon J. Fuller 		void			*elem_outp;
952*77cb4d3eSLandon J. Fuller 		size_t			 elem_nbytes;
953*77cb4d3eSLandon J. Fuller 
954*77cb4d3eSLandon J. Fuller 		/* If the output type is not an array type, we can only encode
955*77cb4d3eSLandon J. Fuller 		 * one element */
956*77cb4d3eSLandon J. Fuller 		nelem++;
957*77cb4d3eSLandon J. Fuller 		if (nelem > 1 && !bhnd_nvram_is_array_type(otype)) {
958*77cb4d3eSLandon J. Fuller 			return (EFTYPE);
959*77cb4d3eSLandon J. Fuller 		}
960*77cb4d3eSLandon J. Fuller 
961*77cb4d3eSLandon J. Fuller 		/* Determine output offset / limit */
962*77cb4d3eSLandon J. Fuller 		if (nbytes >= limit) {
963*77cb4d3eSLandon J. Fuller 			elem_nbytes = 0;
964*77cb4d3eSLandon J. Fuller 			elem_outp = NULL;
965*77cb4d3eSLandon J. Fuller 		} else {
966*77cb4d3eSLandon J. Fuller 			elem_nbytes = limit - nbytes;
967*77cb4d3eSLandon J. Fuller 			elem_outp = (uint8_t *)outp + nbytes;
968*77cb4d3eSLandon J. Fuller 		}
969*77cb4d3eSLandon J. Fuller 
970*77cb4d3eSLandon J. Fuller 		/* Attempt encode */
971*77cb4d3eSLandon J. Fuller 		error = bhnd_nvram_val_encode_elem(value, next, next_len,
972*77cb4d3eSLandon J. Fuller 		    elem_outp, &elem_nbytes, otype_base);
973*77cb4d3eSLandon J. Fuller 
974*77cb4d3eSLandon J. Fuller 		/* If encoding failed for any reason other than ENOMEM (which
975*77cb4d3eSLandon J. Fuller 		 * we'll detect and report below), return immediately */
976*77cb4d3eSLandon J. Fuller 		if (error && error != ENOMEM)
977*77cb4d3eSLandon J. Fuller 			return (error);
978*77cb4d3eSLandon J. Fuller 
979*77cb4d3eSLandon J. Fuller 		/* Add to total length */
980*77cb4d3eSLandon J. Fuller 		if (SIZE_MAX - nbytes < elem_nbytes)
981*77cb4d3eSLandon J. Fuller 			return (EFTYPE); /* would overflow size_t */
982*77cb4d3eSLandon J. Fuller 
983*77cb4d3eSLandon J. Fuller 		nbytes += elem_nbytes;
984*77cb4d3eSLandon J. Fuller 	}
985*77cb4d3eSLandon J. Fuller 
986*77cb4d3eSLandon J. Fuller 	/* Provide the actual length */
987*77cb4d3eSLandon J. Fuller 	*olen = nbytes;
988*77cb4d3eSLandon J. Fuller 
989*77cb4d3eSLandon J. Fuller 	/* If no output was requested, nothing left to do */
990*77cb4d3eSLandon J. Fuller 	if (outp == NULL)
991*77cb4d3eSLandon J. Fuller 		return (0);
992*77cb4d3eSLandon J. Fuller 
993*77cb4d3eSLandon J. Fuller 	/* Otherwise, report a memory error if the output buffer was too
994*77cb4d3eSLandon J. Fuller 	 * small */
995*77cb4d3eSLandon J. Fuller 	if (limit < nbytes)
996*77cb4d3eSLandon J. Fuller 		return (ENOMEM);
997*77cb4d3eSLandon J. Fuller 
998*77cb4d3eSLandon J. Fuller 	return (0);
999*77cb4d3eSLandon J. Fuller }
1000*77cb4d3eSLandon J. Fuller 
1001*77cb4d3eSLandon J. Fuller /**
1002*77cb4d3eSLandon J. Fuller  * Generic implementation of bhnd_nvram_val_op_encode_elem(), compatible with
1003*77cb4d3eSLandon J. Fuller  * all supported NVRAM data types.
1004*77cb4d3eSLandon J. Fuller  */
1005*77cb4d3eSLandon J. Fuller int
1006*77cb4d3eSLandon J. Fuller bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val_t *value, const void *inp,
1007*77cb4d3eSLandon J. Fuller     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
1008*77cb4d3eSLandon J. Fuller {
1009*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type itype;
1010*77cb4d3eSLandon J. Fuller 
1011*77cb4d3eSLandon J. Fuller 	itype = bhnd_nvram_val_elem_type(value);
1012*77cb4d3eSLandon J. Fuller 	switch (itype) {
1013*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
1014*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
1015*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
1016*77cb4d3eSLandon J. Fuller 		return (bhnd_nvram_val_encode_string(outp, olen, otype, inp,
1017*77cb4d3eSLandon J. Fuller 		    ilen, itype));
1018*77cb4d3eSLandon J. Fuller 
1019*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
1020*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
1021*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
1022*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
1023*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
1024*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
1025*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
1026*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
1027*77cb4d3eSLandon J. Fuller 		return (bhnd_nvram_val_encode_int(outp, olen, otype, inp, ilen,
1028*77cb4d3eSLandon J. Fuller 		    itype));
1029*77cb4d3eSLandon J. Fuller 
1030*77cb4d3eSLandon J. Fuller 	default:
1031*77cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("missing encode_elem() implementation");
1032*77cb4d3eSLandon J. Fuller 	}
1033*77cb4d3eSLandon J. Fuller }
1034*77cb4d3eSLandon J. Fuller 
1035*77cb4d3eSLandon J. Fuller /**
1036*77cb4d3eSLandon J. Fuller  * Generic implementation of bhnd_nvram_val_op_next(), compatible with
1037*77cb4d3eSLandon J. Fuller  * all supported NVRAM data types.
1038*77cb4d3eSLandon J. Fuller  */
1039*77cb4d3eSLandon J. Fuller const void *
1040*77cb4d3eSLandon J. Fuller bhnd_nvram_val_generic_next(bhnd_nvram_val_t *value, const void *prev,
1041*77cb4d3eSLandon J. Fuller     size_t *len)
1042*77cb4d3eSLandon J. Fuller {
1043*77cb4d3eSLandon J. Fuller 	const uint8_t	*inp;
1044*77cb4d3eSLandon J. Fuller 	const uint8_t	*next;
1045*77cb4d3eSLandon J. Fuller 	bhnd_nvram_type	 itype;
1046*77cb4d3eSLandon J. Fuller 	size_t		 ilen;
1047*77cb4d3eSLandon J. Fuller 	size_t		 offset;
1048*77cb4d3eSLandon J. Fuller 
1049*77cb4d3eSLandon J. Fuller 	/* Otherwise, default to iterating over the backing representation
1050*77cb4d3eSLandon J. Fuller 	 * according to its native representation */
1051*77cb4d3eSLandon J. Fuller 	inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
1052*77cb4d3eSLandon J. Fuller 
1053*77cb4d3eSLandon J. Fuller 	/* First element */
1054*77cb4d3eSLandon J. Fuller 	if (prev == NULL) {
1055*77cb4d3eSLandon J. Fuller 		/* Zero-length array? */
1056*77cb4d3eSLandon J. Fuller 		if (ilen == 0)
1057*77cb4d3eSLandon J. Fuller 			return (NULL);
1058*77cb4d3eSLandon J. Fuller 
1059*77cb4d3eSLandon J. Fuller 		*len = bhnd_nvram_value_size(itype, inp, ilen, 1);
1060*77cb4d3eSLandon J. Fuller 		return (inp);
1061*77cb4d3eSLandon J. Fuller 	}
1062*77cb4d3eSLandon J. Fuller 
1063*77cb4d3eSLandon J. Fuller 	/* Advance to next element */
1064*77cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(prev >= (const void *)inp, ("invalid cookiep"));
1065*77cb4d3eSLandon J. Fuller 	next = (const uint8_t *)prev + *len;
1066*77cb4d3eSLandon J. Fuller 	offset = (size_t)(next - inp);
1067*77cb4d3eSLandon J. Fuller 
1068*77cb4d3eSLandon J. Fuller 	if (offset >= ilen) {
1069*77cb4d3eSLandon J. Fuller 		/* Hit end of the array */
1070*77cb4d3eSLandon J. Fuller 		return (NULL);
1071*77cb4d3eSLandon J. Fuller 	}
1072*77cb4d3eSLandon J. Fuller 
1073*77cb4d3eSLandon J. Fuller 	/* Determine element size */
1074*77cb4d3eSLandon J. Fuller 	*len = bhnd_nvram_value_size(itype, next, ilen - offset, 1);
1075*77cb4d3eSLandon J. Fuller 	if (ilen - offset < *len)
1076*77cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("short element -- misaligned representation");
1077*77cb4d3eSLandon J. Fuller 
1078*77cb4d3eSLandon J. Fuller 	return (next);
1079*77cb4d3eSLandon J. Fuller }
1080*77cb4d3eSLandon J. Fuller 
1081*77cb4d3eSLandon J. Fuller /**
1082*77cb4d3eSLandon J. Fuller  * Initialize the representation of @p value with @p ptr.
1083*77cb4d3eSLandon J. Fuller  *
1084*77cb4d3eSLandon J. Fuller  * If @p value is an externally allocated instance and the representation
1085*77cb4d3eSLandon J. Fuller  * cannot be represented inline, the given data will not be copied, and @p ptr
1086*77cb4d3eSLandon J. Fuller  * must remain valid for the lifetime of @p value.
1087*77cb4d3eSLandon J. Fuller  *
1088*77cb4d3eSLandon J. Fuller  * Otherwise, @p value will be initialized with a copy of the @p ptr.
1089*77cb4d3eSLandon J. Fuller  *
1090*77cb4d3eSLandon J. Fuller  * @param	value	The value to be initialized.
1091*77cb4d3eSLandon J. Fuller  * @param	inp	The external representation.
1092*77cb4d3eSLandon J. Fuller  * @param	ilen	The external representation length, in bytes.
1093*77cb4d3eSLandon J. Fuller  * @param	itype	The external representation's data type.
1094*77cb4d3eSLandon J. Fuller  * @param	flags	Value flags.
1095*77cb4d3eSLandon J. Fuller  *
1096*77cb4d3eSLandon J. Fuller  * @retval 0		success.
1097*77cb4d3eSLandon J. Fuller  * @retval ENOMEM	if allocation fails
1098*77cb4d3eSLandon J. Fuller  * @retval EFTYPE	if @p itype is not an array type, and @p ilen is not
1099*77cb4d3eSLandon J. Fuller  *			equal to the size of a single element of @p itype.
1100*77cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
1101*77cb4d3eSLandon J. Fuller  *			@p itype.
1102*77cb4d3eSLandon J. Fuller  */
1103*77cb4d3eSLandon J. Fuller static int
1104*77cb4d3eSLandon J. Fuller bhnd_nvram_val_set(bhnd_nvram_val_t *value, const void *inp, size_t ilen,
1105*77cb4d3eSLandon J. Fuller     bhnd_nvram_type itype, uint32_t flags)
1106*77cb4d3eSLandon J. Fuller {
1107*77cb4d3eSLandon J. Fuller 	void	*bytes;
1108*77cb4d3eSLandon J. Fuller 
1109*77cb4d3eSLandon J. Fuller 	BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1110*77cb4d3eSLandon J. Fuller 
1111*77cb4d3eSLandon J. Fuller 	/* Reference the external data */
1112*77cb4d3eSLandon J. Fuller 	if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
1113*77cb4d3eSLandon J. Fuller 	    (flags & BHND_NVRAM_VAL_STATIC_DATA))
1114*77cb4d3eSLandon J. Fuller 	{
1115*77cb4d3eSLandon J. Fuller 		if (flags & BHND_NVRAM_VAL_BORROW_DATA)
1116*77cb4d3eSLandon J. Fuller 			value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
1117*77cb4d3eSLandon J. Fuller 		else
1118*77cb4d3eSLandon J. Fuller 			value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
1119*77cb4d3eSLandon J. Fuller 
1120*77cb4d3eSLandon J. Fuller 		value->data.ptr = inp;
1121*77cb4d3eSLandon J. Fuller 		value->data_type = itype;
1122*77cb4d3eSLandon J. Fuller 		value->data_len = ilen;
1123*77cb4d3eSLandon J. Fuller 		return (0);
1124*77cb4d3eSLandon J. Fuller 	}
1125*77cb4d3eSLandon J. Fuller 
1126*77cb4d3eSLandon J. Fuller 	/* Fetch reference to (or allocate) an appropriately sized buffer */
1127*77cb4d3eSLandon J. Fuller 	bytes = bhnd_nvram_val_alloc_bytes(value, ilen, itype, flags);
1128*77cb4d3eSLandon J. Fuller 	if (bytes == NULL)
1129*77cb4d3eSLandon J. Fuller 		return (ENOMEM);
1130*77cb4d3eSLandon J. Fuller 
1131*77cb4d3eSLandon J. Fuller 	/* Copy data */
1132*77cb4d3eSLandon J. Fuller 	memcpy(bytes, inp, ilen);
1133*77cb4d3eSLandon J. Fuller 
1134*77cb4d3eSLandon J. Fuller 	return (0);
1135*77cb4d3eSLandon J. Fuller }
1136*77cb4d3eSLandon J. Fuller 
1137*77cb4d3eSLandon J. Fuller /**
1138*77cb4d3eSLandon J. Fuller  * Initialize the internal inline representation of @p value with a copy of
1139*77cb4d3eSLandon J. Fuller  * the data referenced by @p inp of @p itype.
1140*77cb4d3eSLandon J. Fuller  *
1141*77cb4d3eSLandon J. Fuller  * If @p inp is NULL, @p itype and @p ilen will be validated, but no data will
1142*77cb4d3eSLandon J. Fuller  * be copied.
1143*77cb4d3eSLandon J. Fuller  *
1144*77cb4d3eSLandon J. Fuller  * @param	value	The value to be initialized.
1145*77cb4d3eSLandon J. Fuller  * @param	inp	The input data to be copied, or NULL to verify
1146*77cb4d3eSLandon J. Fuller  *			that data of @p ilen and @p itype can be represented
1147*77cb4d3eSLandon J. Fuller  *			inline.
1148*77cb4d3eSLandon J. Fuller  * @param	ilen	The size of the external buffer to be allocated.
1149*77cb4d3eSLandon J. Fuller  * @param	itype	The type of the external buffer to be allocated.
1150*77cb4d3eSLandon J. Fuller  *
1151*77cb4d3eSLandon J. Fuller  * @retval 0		success
1152*77cb4d3eSLandon J. Fuller  * @retval ENOMEM	if @p ilen is too large to be represented inline.
1153*77cb4d3eSLandon J. Fuller  * @retval EFAULT	if @p ilen is not correctly aligned for elements of
1154*77cb4d3eSLandon J. Fuller  *			@p itype.
1155*77cb4d3eSLandon J. Fuller  */
1156*77cb4d3eSLandon J. Fuller static int
1157*77cb4d3eSLandon J. Fuller bhnd_nvram_val_set_inline(bhnd_nvram_val_t *value, const void *inp, size_t ilen,
1158*77cb4d3eSLandon J. Fuller     bhnd_nvram_type itype)
1159*77cb4d3eSLandon J. Fuller {
1160*77cb4d3eSLandon J. Fuller 	BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1161*77cb4d3eSLandon J. Fuller 
1162*77cb4d3eSLandon J. Fuller #define	NV_STORE_INIT_INLINE()	do {					\
1163*77cb4d3eSLandon J. Fuller 	value->data_len = ilen;						\
1164*77cb4d3eSLandon J. Fuller } while(0)
1165*77cb4d3eSLandon J. Fuller 
1166*77cb4d3eSLandon J. Fuller #define	NV_STORE_INLINE(_type, _dest)	do {				\
1167*77cb4d3eSLandon J. Fuller 	if (ilen != sizeof(_type))					\
1168*77cb4d3eSLandon J. Fuller 		return (EFAULT);					\
1169*77cb4d3eSLandon J. Fuller 									\
1170*77cb4d3eSLandon J. Fuller 	if (inp != NULL) {						\
1171*77cb4d3eSLandon J. Fuller 		value->data._dest[0] = *(const _type *)inp;		\
1172*77cb4d3eSLandon J. Fuller 		NV_STORE_INIT_INLINE();					\
1173*77cb4d3eSLandon J. Fuller 	}								\
1174*77cb4d3eSLandon J. Fuller } while (0)
1175*77cb4d3eSLandon J. Fuller 
1176*77cb4d3eSLandon J. Fuller #define	NV_COPY_ARRRAY_INLINE(_type, _dest)	do {		\
1177*77cb4d3eSLandon J. Fuller 	if (ilen % sizeof(_type) != 0)				\
1178*77cb4d3eSLandon J. Fuller 		return (EFAULT);				\
1179*77cb4d3eSLandon J. Fuller 								\
1180*77cb4d3eSLandon J. Fuller 	if (ilen > nitems(value->data. _dest))			\
1181*77cb4d3eSLandon J. Fuller 		return (ENOMEM);				\
1182*77cb4d3eSLandon J. Fuller 								\
1183*77cb4d3eSLandon J. Fuller 	if (inp == NULL)					\
1184*77cb4d3eSLandon J. Fuller 		return (0);					\
1185*77cb4d3eSLandon J. Fuller 								\
1186*77cb4d3eSLandon J. Fuller 	memcpy(&value->data._dest, inp, ilen);			\
1187*77cb4d3eSLandon J. Fuller 	if (inp != NULL) {					\
1188*77cb4d3eSLandon J. Fuller 		memcpy(&value->data._dest, inp, ilen);		\
1189*77cb4d3eSLandon J. Fuller 		NV_STORE_INIT_INLINE();				\
1190*77cb4d3eSLandon J. Fuller 	}							\
1191*77cb4d3eSLandon J. Fuller } while (0)
1192*77cb4d3eSLandon J. Fuller 
1193*77cb4d3eSLandon J. Fuller 	/* Attempt to copy to inline storage */
1194*77cb4d3eSLandon J. Fuller 	switch (itype) {
1195*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
1196*77cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint8_t, ch);
1197*77cb4d3eSLandon J. Fuller 		return (0);
1198*77cb4d3eSLandon J. Fuller 
1199*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
1200*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
1201*77cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint8_t, u8);
1202*77cb4d3eSLandon J. Fuller 		return (0);
1203*77cb4d3eSLandon J. Fuller 
1204*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
1205*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
1206*77cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint16_t, u16);
1207*77cb4d3eSLandon J. Fuller 		return (0);
1208*77cb4d3eSLandon J. Fuller 
1209*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
1210*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
1211*77cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint32_t, u32);
1212*77cb4d3eSLandon J. Fuller 		return (0);
1213*77cb4d3eSLandon J. Fuller 
1214*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
1215*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
1216*77cb4d3eSLandon J. Fuller 		NV_STORE_INLINE(uint32_t, u32);
1217*77cb4d3eSLandon J. Fuller 		return (0);
1218*77cb4d3eSLandon J. Fuller 
1219*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
1220*77cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint8_t, ch);
1221*77cb4d3eSLandon J. Fuller 		return (0);
1222*77cb4d3eSLandon J. Fuller 
1223*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
1224*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
1225*77cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint8_t, u8);
1226*77cb4d3eSLandon J. Fuller 		return (0);
1227*77cb4d3eSLandon J. Fuller 
1228*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
1229*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
1230*77cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint16_t, u16);
1231*77cb4d3eSLandon J. Fuller 		return (0);
1232*77cb4d3eSLandon J. Fuller 
1233*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
1234*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
1235*77cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint32_t, u32);
1236*77cb4d3eSLandon J. Fuller 		return (0);
1237*77cb4d3eSLandon J. Fuller 
1238*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
1239*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
1240*77cb4d3eSLandon J. Fuller 		NV_COPY_ARRRAY_INLINE(uint64_t, u64);
1241*77cb4d3eSLandon J. Fuller 		return (0);
1242*77cb4d3eSLandon J. Fuller 
1243*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
1244*77cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
1245*77cb4d3eSLandon J. Fuller 		if (ilen > sizeof(value->data.ch))
1246*77cb4d3eSLandon J. Fuller 			return (ENOMEM);
1247*77cb4d3eSLandon J. Fuller 
1248*77cb4d3eSLandon J. Fuller 		if (inp != NULL) {
1249*77cb4d3eSLandon J. Fuller 			memcpy(&value->data.ch, inp, ilen);
1250*77cb4d3eSLandon J. Fuller 			NV_STORE_INIT_INLINE();
1251*77cb4d3eSLandon J. Fuller 		}
1252*77cb4d3eSLandon J. Fuller 
1253*77cb4d3eSLandon J. Fuller 		return (0);
1254*77cb4d3eSLandon J. Fuller 	}
1255*77cb4d3eSLandon J. Fuller 
1256*77cb4d3eSLandon J. Fuller #undef	NV_STORE_INIT_INLINE
1257*77cb4d3eSLandon J. Fuller #undef	NV_STORE_INLINE
1258*77cb4d3eSLandon J. Fuller #undef	NV_COPY_ARRRAY_INLINE
1259*77cb4d3eSLandon J. Fuller 
1260*77cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("unknown data type %d", itype);
1261*77cb4d3eSLandon J. Fuller }
1262*77cb4d3eSLandon J. Fuller 
1263*77cb4d3eSLandon J. Fuller /**
1264*77cb4d3eSLandon J. Fuller  * Initialize the internal representation of @p value with a buffer allocation
1265*77cb4d3eSLandon J. Fuller  * of @p len and @p itype, returning a pointer to the allocated buffer.
1266*77cb4d3eSLandon J. Fuller  *
1267*77cb4d3eSLandon J. Fuller  * If a buffer of @p len and @p itype can be represented inline, no
1268*77cb4d3eSLandon J. Fuller  * external buffer will be allocated, and instead a pointer to the inline
1269*77cb4d3eSLandon J. Fuller  * data representation will be returned.
1270*77cb4d3eSLandon J. Fuller  *
1271*77cb4d3eSLandon J. Fuller  * @param	value	The value to be initialized.
1272*77cb4d3eSLandon J. Fuller  * @param	ilen	The size of the external buffer to be allocated.
1273*77cb4d3eSLandon J. Fuller  * @param	itype	The type of the external buffer to be allocated.
1274*77cb4d3eSLandon J. Fuller  * @param	flags	Value flags.
1275*77cb4d3eSLandon J. Fuller  *
1276*77cb4d3eSLandon J. Fuller  * @retval non-null	The newly allocated buffer.
1277*77cb4d3eSLandon J. Fuller  * @retval NULL		If allocation failed.
1278*77cb4d3eSLandon J. Fuller  * @retval NULL		If @p value is an externally allocated instance.
1279*77cb4d3eSLandon J. Fuller  */
1280*77cb4d3eSLandon J. Fuller static void *
1281*77cb4d3eSLandon J. Fuller bhnd_nvram_val_alloc_bytes(bhnd_nvram_val_t *value, size_t ilen,
1282*77cb4d3eSLandon J. Fuller     bhnd_nvram_type itype, uint32_t flags)
1283*77cb4d3eSLandon J. Fuller {
1284*77cb4d3eSLandon J. Fuller 	void *ptr;
1285*77cb4d3eSLandon J. Fuller 
1286*77cb4d3eSLandon J. Fuller 	BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1287*77cb4d3eSLandon J. Fuller 
1288*77cb4d3eSLandon J. Fuller 	/* Can we use inline storage? */
1289*77cb4d3eSLandon J. Fuller 	if (bhnd_nvram_val_set_inline(value, NULL, ilen, itype) == 0) {
1290*77cb4d3eSLandon J. Fuller 		BHND_NV_ASSERT(sizeof(value->data) >= ilen,
1291*77cb4d3eSLandon J. Fuller 		    ("ilen exceeds inline storage"));
1292*77cb4d3eSLandon J. Fuller 
1293*77cb4d3eSLandon J. Fuller 		value->data_type = itype;
1294*77cb4d3eSLandon J. Fuller 		value->data_len = ilen;
1295*77cb4d3eSLandon J. Fuller 		value->data_storage = BHND_NVRAM_VAL_DATA_INLINE;
1296*77cb4d3eSLandon J. Fuller 		return (&value->data);
1297*77cb4d3eSLandon J. Fuller 	}
1298*77cb4d3eSLandon J. Fuller 
1299*77cb4d3eSLandon J. Fuller 	/* Is allocation permitted? */
1300*77cb4d3eSLandon J. Fuller 	if (!(flags & BHND_NVRAM_VAL_DYNAMIC))
1301*77cb4d3eSLandon J. Fuller 		return (NULL);
1302*77cb4d3eSLandon J. Fuller 
1303*77cb4d3eSLandon J. Fuller 	/* Allocate external storage */
1304*77cb4d3eSLandon J. Fuller 	if ((ptr = bhnd_nv_malloc(ilen)) == NULL)
1305*77cb4d3eSLandon J. Fuller 		return (NULL);
1306*77cb4d3eSLandon J. Fuller 
1307*77cb4d3eSLandon J. Fuller 	value->data.ptr = ptr;
1308*77cb4d3eSLandon J. Fuller 	value->data_len = ilen;
1309*77cb4d3eSLandon J. Fuller 	value->data_type = itype;
1310*77cb4d3eSLandon J. Fuller 	value->data_storage = BHND_NVRAM_VAL_DATA_EXT_ALLOC;
1311*77cb4d3eSLandon J. Fuller 
1312*77cb4d3eSLandon J. Fuller 	return (ptr);
1313*77cb4d3eSLandon J. Fuller }
1314