2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
38 #include <sys/ctype.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/systm.h>
43 #include <machine/_inttypes.h>
55 #include "bhnd_nvram_private.h"
57 #include "bhnd_nvram_valuevar.h"
59 static int bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
60 const void *inp, size_t ilen, bhnd_nvram_type itype);
62 static void *bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
63 bhnd_nvram_type itype, uint32_t flags);
64 static int bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp,
65 size_t ilen, bhnd_nvram_type itype, uint32_t flags);
66 static int bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
67 const void *inp, size_t ilen, bhnd_nvram_type itype);
70 static int bhnd_nvram_val_encode_data(const void *inp, size_t ilen,
71 bhnd_nvram_type itype, void *outp, size_t *olen,
72 bhnd_nvram_type otype);
73 static int bhnd_nvram_val_encode_int(const void *inp, size_t ilen,
74 bhnd_nvram_type itype, void *outp, size_t *olen,
75 bhnd_nvram_type otype);
76 static int bhnd_nvram_val_encode_null(const void *inp, size_t ilen,
77 bhnd_nvram_type itype, void *outp, size_t *olen,
78 bhnd_nvram_type otype);
79 static int bhnd_nvram_val_encode_bool(const void *inp, size_t ilen,
80 bhnd_nvram_type itype, void *outp, size_t *olen,
81 bhnd_nvram_type otype);
82 static int bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
83 bhnd_nvram_type itype, void *outp, size_t *olen,
84 bhnd_nvram_type otype);
86 /** Initialize an empty value instance with @p _fmt, @p _storage, and
87 * an implicit callee-owned reference */
88 #define BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage) \
91 .val_storage = _storage, \
93 .data_storage = BHND_NVRAM_VAL_DATA_NONE, \
96 /** Assert that @p value's backing representation state has initialized
98 #define BHND_NVRAM_VAL_ASSERT_EMPTY(_value) \
100 value->data_storage == BHND_NVRAM_VAL_DATA_NONE && \
101 value->data_len == 0 && \
102 value->data.ptr == NULL, \
103 ("previously initialized value"))
105 /** Return true if BHND_NVRAM_VAL_BORROW_DATA or BHND_NVRAM_VAL_STATIC_DATA is
106 * set in @p _flags (e.g. we should attempt to directly reference external
108 #define BHND_NVRAM_VAL_EXTREF_BORROWED_DATA(_flags) \
109 (((_flags) & BHND_NVRAM_VAL_BORROW_DATA) || \
110 ((_flags) & BHND_NVRAM_VAL_STATIC_DATA))
112 /** Flags permitted when performing val-based initialization via
113 * bhnd_nvram_val_convert_init() or bhnd_nvram_val_convert_new() */
114 #define BHND_NVRAM_VALID_CONV_FLAGS \
115 (BHND_NVRAM_VAL_FIXED | \
116 BHND_NVRAM_VAL_DYNAMIC | \
117 BHND_NVRAM_VAL_COPY_DATA)
119 /** Returns true if @p _val must be copied in bhnd_nvram_val_copy(), false
120 * if its reference count may be safely incremented */
121 #define BHND_NVRAM_VAL_NEED_COPY(_val) \
122 ((_val)->val_storage == BHND_NVRAM_VAL_STORAGE_AUTO || \
123 (_val)->data_storage == BHND_NVRAM_VAL_DATA_EXT_WEAK)
125 volatile u_int refs; /**< reference count */
126 bhnd_nvram_val_storage val_storage; /**< value structure storage */
127 const bhnd_nvram_val_fmt *fmt; /**< value format */
128 bhnd_nvram_val_data_storage data_storage; /**< data storage */
129 bhnd_nvram_type data_type; /**< data type */
130 size_t data_len; /**< data size */
132 /* Shared NULL value instance */
133 bhnd_nvram_val bhnd_nvram_val_null = {
135 .val_storage = BHND_NVRAM_VAL_STORAGE_STATIC,
136 .fmt = &bhnd_nvram_val_null_fmt,
137 .data_storage = BHND_NVRAM_VAL_DATA_INLINE,
138 .data_type = BHND_NVRAM_TYPE_NULL,
143 * Return the human-readable name of @p fmt.
146 bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt *fmt)
152 * Return the default format for values of @p type.
154 const bhnd_nvram_val_fmt *
155 bhnd_nvram_val_default_fmt(bhnd_nvram_type type)
158 case BHND_NVRAM_TYPE_UINT8:
159 return (&bhnd_nvram_val_uint8_fmt);
160 case BHND_NVRAM_TYPE_UINT16:
161 return (&bhnd_nvram_val_uint16_fmt);
162 case BHND_NVRAM_TYPE_UINT32:
163 return (&bhnd_nvram_val_uint32_fmt);
164 case BHND_NVRAM_TYPE_UINT64:
165 return (&bhnd_nvram_val_uint64_fmt);
166 case BHND_NVRAM_TYPE_INT8:
167 return (&bhnd_nvram_val_int8_fmt);
168 case BHND_NVRAM_TYPE_INT16:
169 return (&bhnd_nvram_val_int16_fmt);
170 case BHND_NVRAM_TYPE_INT32:
171 return (&bhnd_nvram_val_int32_fmt);
172 case BHND_NVRAM_TYPE_INT64:
173 return (&bhnd_nvram_val_int64_fmt);
174 case BHND_NVRAM_TYPE_CHAR:
175 return (&bhnd_nvram_val_char_fmt);
176 case BHND_NVRAM_TYPE_STRING:
177 return (&bhnd_nvram_val_string_fmt);
178 case BHND_NVRAM_TYPE_BOOL:
179 return (&bhnd_nvram_val_bool_fmt);
180 case BHND_NVRAM_TYPE_NULL:
181 return (&bhnd_nvram_val_null_fmt);
182 case BHND_NVRAM_TYPE_DATA:
183 return (&bhnd_nvram_val_data_fmt);
184 case BHND_NVRAM_TYPE_UINT8_ARRAY:
185 return (&bhnd_nvram_val_uint8_array_fmt);
186 case BHND_NVRAM_TYPE_UINT16_ARRAY:
187 return (&bhnd_nvram_val_uint16_array_fmt);
188 case BHND_NVRAM_TYPE_UINT32_ARRAY:
189 return (&bhnd_nvram_val_uint32_array_fmt);
190 case BHND_NVRAM_TYPE_UINT64_ARRAY:
191 return (&bhnd_nvram_val_uint64_array_fmt);
192 case BHND_NVRAM_TYPE_INT8_ARRAY:
193 return (&bhnd_nvram_val_int8_array_fmt);
194 case BHND_NVRAM_TYPE_INT16_ARRAY:
195 return (&bhnd_nvram_val_int16_array_fmt);
196 case BHND_NVRAM_TYPE_INT32_ARRAY:
197 return (&bhnd_nvram_val_int32_array_fmt);
198 case BHND_NVRAM_TYPE_INT64_ARRAY:
199 return (&bhnd_nvram_val_int64_array_fmt);
200 case BHND_NVRAM_TYPE_CHAR_ARRAY:
201 return (&bhnd_nvram_val_char_array_fmt);
202 case BHND_NVRAM_TYPE_STRING_ARRAY:
203 return (&bhnd_nvram_val_string_array_fmt);
204 case BHND_NVRAM_TYPE_BOOL_ARRAY:
205 return (&bhnd_nvram_val_bool_array_fmt);
209 BHND_NV_PANIC("bhnd nvram type %u unknown", type);
213 * Determine whether @p fmt (or new format delegated to by @p fmt) is
214 * capable of direct initialization from buffer @p inp.
216 * @param[in,out] fmt Indirect pointer to the NVRAM value format. If
217 * the format instance cannot handle the data type
218 * directly, it may delegate to a new format
219 * instance. On success, this parameter will be
220 * set to the format that should be used when
221 * performing initialization from @p inp.
222 * @param inp Input data.
223 * @param ilen Input data length.
224 * @param itype Input data type.
226 * @retval 0 If initialization from @p inp is supported.
227 * @retval EFTYPE If initialization from @p inp is unsupported.
228 * @retval EFAULT if @p ilen is not correctly aligned for elements of
232 bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
233 size_t ilen, bhnd_nvram_type itype)
235 const bhnd_nvram_val_fmt *ofmt, *nfmt;
240 /* Validate alignment */
241 if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
244 /* If the format does not provide a filter function, it only supports
245 * direct initialization from its native type */
246 if (ofmt->op_filter == NULL) {
247 if (itype == ofmt->native_type)
253 /* Use the filter function to determine whether direct initialization
254 * from itype is permitted */
255 error = ofmt->op_filter(&nfmt, inp, ilen, itype);
259 /* Retry filter with new format? */
261 error = bhnd_nvram_val_fmt_filter(&nfmt, inp, ilen, itype);
265 /* Success -- provide delegated format to caller */
269 /* Value can be initialized with provided format and input type */
273 /* Common initialization support for bhnd_nvram_val_init() and
274 * bhnd_nvram_val_new() */
276 bhnd_nvram_val_init_common(bhnd_nvram_val *value,
277 bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
278 const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
281 bhnd_nvram_type otype;
285 /* If the value format is unspecified, we use the default format
286 * for the input data type */
288 fmt = bhnd_nvram_val_default_fmt(itype);
290 /* Determine expected data type, and allow the format to delegate to
291 * a new format instance */
292 if ((error = bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype))) {
293 /* Direct initialization from the provided input type is
294 * not supported; alue must be initialized with the format's
296 otype = fmt->native_type;
298 /* Value can be initialized with provided input type */
302 /* Initialize value instance */
303 *value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
305 /* If input data already in native format, init directly. */
306 if (otype == itype) {
307 error = bhnd_nvram_val_set(value, inp, ilen, itype, flags);
314 /* Determine size when encoded in native format */
315 error = bhnd_nvram_value_coerce(inp, ilen, itype, NULL, &olen, otype);
319 /* Fetch reference to (or allocate) an appropriately sized buffer */
320 outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
325 error = bhnd_nvram_value_coerce(inp, ilen, itype, outp, &olen, otype);
333 * Initialize an externally allocated instance of @p value with @p fmt from the
334 * given @p inp buffer of @p itype and @p ilen.
336 * On success, the caller owns a reference to @p value, and is responsible for
337 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
339 * @param value The externally allocated value instance to be
341 * @param fmt The value's format, or NULL to use the default format
343 * @param inp Input buffer.
344 * @param ilen Input buffer length.
345 * @param itype Input buffer type.
346 * @param flags Value flags (see BHND_NVRAM_VAL_*).
349 * @retval ENOMEM If allocation fails.
350 * @retval EFTYPE If @p fmt initialization from @p itype is unsupported.
351 * @retval EFAULT if @p ilen is not correctly aligned for elements of
353 * @retval ERANGE If value coercion would overflow (or underflow) the
354 * @p fmt representation.
357 bhnd_nvram_val_init(bhnd_nvram_val *value, const bhnd_nvram_val_fmt *fmt,
358 const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
362 error = bhnd_nvram_val_init_common(value, BHND_NVRAM_VAL_STORAGE_AUTO,
363 fmt, inp, ilen, itype, flags);
365 bhnd_nvram_val_release(value);
371 * Allocate a value instance with @p fmt, and attempt to initialize its internal
372 * representation from the given @p inp buffer of @p itype and @p ilen.
374 * On success, the caller owns a reference to @p value, and is responsible for
375 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
377 * @param[out] value On success, the allocated value instance.
378 * @param fmt The value's format, or NULL to use the default format
380 * @param inp Input buffer.
381 * @param ilen Input buffer length.
382 * @param itype Input buffer type.
383 * @param flags Value flags (see BHND_NVRAM_VAL_*).
386 * @retval ENOMEM If allocation fails.
387 * @retval EFTYPE If @p fmt initialization from @p itype is unsupported.
388 * @retval EFAULT if @p ilen is not correctly aligned for elements of
390 * @retval ERANGE If value coercion would overflow (or underflow) the
391 * @p fmt representation.
394 bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
395 const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
399 /* Allocate new instance */
400 if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
403 /* Perform common initialization. */
404 error = bhnd_nvram_val_init_common(*value,
405 BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, inp, ilen, itype, flags);
407 /* Will also free() the value allocation */
408 bhnd_nvram_val_release(*value);
415 /* Common initialization support for bhnd_nvram_val_convert_init() and
416 * bhnd_nvram_val_convert_new() */
418 bhnd_nvram_val_convert_common(bhnd_nvram_val *value,
419 bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
420 bhnd_nvram_val *src, uint32_t flags)
424 bhnd_nvram_type itype, otype;
428 /* Determine whether direct initialization from the source value's
429 * existing data type is supported by the new format */
430 inp = bhnd_nvram_val_bytes(src, &ilen, &itype);
431 if (bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype) == 0) {
432 /* Adjust value flags based on the source data storage */
433 switch (src->data_storage) {
434 case BHND_NVRAM_VAL_DATA_NONE:
435 case BHND_NVRAM_VAL_DATA_INLINE:
436 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
437 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
440 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
441 /* If the source data has static storage duration,
442 * we should apply that transitively */
443 if (flags & BHND_NVRAM_VAL_BORROW_DATA)
444 flags |= BHND_NVRAM_VAL_STATIC_DATA;
449 /* Delegate to standard initialization */
450 return (bhnd_nvram_val_init_common(value, val_storage, fmt, inp,
451 ilen, itype, flags));
454 /* Value must be initialized with the format's native type */
455 otype = fmt->native_type;
457 /* Initialize value instance */
458 *value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
460 /* Determine size when encoded in native format */
461 if ((error = bhnd_nvram_val_encode(src, NULL, &olen, otype)))
464 /* Fetch reference to (or allocate) an appropriately sized buffer */
465 outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
470 if ((error = bhnd_nvram_val_encode(src, outp, &olen, otype)))
477 * Initialize an externally allocated instance of @p value with @p fmt, and
478 * attempt to initialize its internal representation from the given @p src
481 * On success, the caller owns a reference to @p value, and is responsible for
482 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
484 * @param value The externally allocated value instance to be
486 * @param fmt The value's format.
487 * @param src Input value to be converted.
488 * @param flags Value flags (see BHND_NVRAM_VAL_*).
491 * @retval ENOMEM If allocation fails.
492 * @retval EFTYPE If @p fmt initialization from @p src is unsupported.
493 * @retval EFAULT if @p ilen is not correctly aligned for elements of
495 * @retval ERANGE If value coercion of @p src would overflow
496 * (or underflow) the @p fmt representation.
499 bhnd_nvram_val_convert_init(bhnd_nvram_val *value,
500 const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
504 error = bhnd_nvram_val_convert_common(value,
505 BHND_NVRAM_VAL_STORAGE_AUTO, fmt, src, flags);
507 bhnd_nvram_val_release(value);
513 * Allocate a value instance with @p fmt, and attempt to initialize its internal
514 * representation from the given @p src value.
516 * On success, the caller owns a reference to @p value, and is responsible for
517 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
519 * @param[out] value On success, the allocated value instance.
520 * @param fmt The value's format.
521 * @param src Input value to be converted.
522 * @param flags Value flags (see BHND_NVRAM_VAL_*).
525 * @retval ENOMEM If allocation fails.
526 * @retval EFTYPE If @p fmt initialization from @p src is unsupported.
527 * @retval EFAULT if @p ilen is not correctly aligned for elements of
529 * @retval ERANGE If value coercion of @p src would overflow
530 * (or underflow) the @p fmt representation.
533 bhnd_nvram_val_convert_new(bhnd_nvram_val **value,
534 const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
538 /* Allocate new instance */
539 if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
542 /* Perform common initialization. */
543 error = bhnd_nvram_val_convert_common(*value,
544 BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, src, flags);
546 /* Will also free() the value allocation */
547 bhnd_nvram_val_release(*value);
554 * Copy or retain a reference to @p value.
556 * On success, the caller is responsible for freeing the result via
557 * bhnd_nvram_val_release().
559 * @param value The value to be copied (or retained).
561 * @retval bhnd_nvram_val if @p value was successfully copied or retained.
562 * @retval NULL if allocation failed.
565 bhnd_nvram_val_copy(bhnd_nvram_val *value)
567 bhnd_nvram_val *result;
569 bhnd_nvram_type type;
574 switch (value->val_storage) {
575 case BHND_NVRAM_VAL_STORAGE_STATIC:
576 /* If static, can return as-is */
579 case BHND_NVRAM_VAL_STORAGE_DYNAMIC:
580 if (!BHND_NVRAM_VAL_NEED_COPY(value)) {
581 refcount_acquire(&value->refs);
585 /* Perform copy below */
588 case BHND_NVRAM_VAL_STORAGE_AUTO:
589 BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
590 "active refcount (%u)", value->refs));
592 /* Perform copy below */
597 /* Compute the new value's flags based on the source value */
598 switch (value->data_storage) {
599 case BHND_NVRAM_VAL_DATA_NONE:
600 case BHND_NVRAM_VAL_DATA_INLINE:
601 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
602 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
603 /* Copy the source data and permit additional allocation if the
604 * value cannot be represented inline */
605 flags = BHND_NVRAM_VAL_COPY_DATA|BHND_NVRAM_VAL_DYNAMIC;
607 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
608 flags = BHND_NVRAM_VAL_STATIC_DATA;
611 BHND_NV_PANIC("invalid storage type: %d", value->data_storage);
614 /* Allocate new value copy */
615 bytes = bhnd_nvram_val_bytes(value, &len, &type);
616 error = bhnd_nvram_val_new(&result, value->fmt, bytes, len, type,
619 BHND_NV_LOG("copy failed: %d", error);
627 * Release a reference to @p value.
629 * If this is the last reference, all associated resources will be freed.
631 * @param value The value to be released.
634 bhnd_nvram_val_release(bhnd_nvram_val *value)
636 BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
638 /* Skip if value is static */
639 if (value->val_storage == BHND_NVRAM_VAL_STORAGE_STATIC)
643 if (!refcount_release(&value->refs))
646 /* Free allocated external representation data */
647 switch (value->data_storage) {
648 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
649 bhnd_nv_free(__DECONST(void *, value->data.ptr));
651 case BHND_NVRAM_VAL_DATA_NONE:
652 case BHND_NVRAM_VAL_DATA_INLINE:
653 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
654 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
655 /* Nothing to free */
659 /* Free instance if dynamically allocated */
660 if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
665 * Standard BHND_NVRAM_TYPE_NULL encoding implementation.
668 bhnd_nvram_val_encode_null(const void *inp, size_t ilen, bhnd_nvram_type itype,
669 void *outp, size_t *olen, bhnd_nvram_type otype)
671 size_t limit, nbytes;
673 BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_NULL,
674 ("unsupported type: %d", itype));
676 /* Determine output byte limit */
684 /* Write to output */
686 case BHND_NVRAM_TYPE_NULL:
687 /* Can be directly encoded as a zero-length NULL value */
691 /* Not representable */
695 /* Provide required length */
708 * Standard BHND_NVRAM_TYPE_BOOL encoding implementation.
711 bhnd_nvram_val_encode_bool(const void *inp, size_t ilen, bhnd_nvram_type itype,
712 void *outp, size_t *olen, bhnd_nvram_type otype)
714 bhnd_nvram_bool_t bval;
715 size_t limit, nbytes, nelem;
718 BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_BOOL,
719 ("unsupported type: %d", itype));
721 /* Determine output byte limit */
727 /* Must be exactly one element in input */
728 if ((error = bhnd_nvram_value_nelem(inp, ilen, itype, &nelem)))
734 /* Fetch (and normalize) boolean value */
735 bval = (*(const bhnd_nvram_bool_t *)inp != 0) ? true : false;
737 /* Write to output */
739 case BHND_NVRAM_TYPE_NULL:
740 /* False can be directly encoded as a zero-length NULL value */
747 case BHND_NVRAM_TYPE_STRING:
748 case BHND_NVRAM_TYPE_STRING_ARRAY: {
749 /* Can encode as "true" or "false" */
750 const char *str = bval ? "true" : "false";
752 nbytes = strlen(str) + 1;
760 /* If output type is an integer, we can delegate to standard
761 * integer encoding to encode as zero or one. */
762 if (bhnd_nvram_is_int_type(otype)) {
763 uint8_t ival = bval ? 1 : 0;
765 return (bhnd_nvram_val_encode_int(&ival, sizeof(ival),
766 BHND_NVRAM_TYPE_UINT8, outp, olen, otype));
769 /* Otherwise not representable */
773 /* Provide required length */
786 * Standard BHND_NVRAM_TYPE_DATA encoding implementation.
789 bhnd_nvram_val_encode_data(const void *inp, size_t ilen, bhnd_nvram_type itype,
790 void *outp, size_t *olen, bhnd_nvram_type otype)
792 BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_DATA,
793 ("unsupported type: %d", itype));
795 /* Write to output */
797 case BHND_NVRAM_TYPE_STRING:
798 case BHND_NVRAM_TYPE_STRING_ARRAY:
799 /* If encoding as a string, produce an EFI-style hexadecimal
800 * byte array (HF1F...) by interpreting the octet string
801 * as an array of uint8 values */
802 return (bhnd_nvram_value_printf("H%[]02hhX", inp, ilen,
803 BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, ""));
806 /* Fall back on direct interpretation as an array of 8-bit
808 return (bhnd_nvram_value_coerce(inp, ilen,
809 BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, otype));
815 * Standard string/char array/char encoding implementation.
817 * Input type must be one of:
818 * - BHND_NVRAM_TYPE_STRING
819 * - BHND_NVRAM_TYPE_CHAR
820 * - BHND_NVRAM_TYPE_CHAR_ARRAY
823 bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
824 bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype)
827 bhnd_nvram_type otype_base;
828 size_t cstr_size, cstr_len;
829 size_t limit, nbytes;
832 itype == BHND_NVRAM_TYPE_STRING ||
833 itype == BHND_NVRAM_TYPE_CHAR ||
834 itype == BHND_NVRAM_TYPE_CHAR_ARRAY,
835 ("unsupported type: %d", itype));
840 otype_base = bhnd_nvram_base_type(otype);
842 /* Determine output byte limit */
848 /* Determine string length, minus trailing NUL (if any) */
849 cstr_len = strnlen(cstr, cstr_size);
851 /* Parse the string data and write to output */
853 case BHND_NVRAM_TYPE_NULL:
854 /* Only an empty string may be represented as a NULL value */
861 case BHND_NVRAM_TYPE_CHAR:
862 case BHND_NVRAM_TYPE_CHAR_ARRAY:
863 /* String must contain exactly 1 non-terminating-NUL character
864 * to be represented as a single char */
865 if (!bhnd_nvram_is_array_type(otype)) {
870 /* Copy out the characters directly (excluding trailing NUL) */
871 for (size_t i = 0; i < cstr_len; i++) {
873 *((uint8_t *)outp + nbytes) = cstr[i];
877 /* Provide required length */
879 if (limit < *olen && outp != NULL)
884 case BHND_NVRAM_TYPE_BOOL:
885 case BHND_NVRAM_TYPE_BOOL_ARRAY: {
888 bhnd_nvram_bool_t bval;
890 /* Trim leading/trailing whitespace */
892 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
894 /* Parse string representation */
895 if (strncasecmp(p, "true", plen) == 0 ||
896 strncasecmp(p, "yes", plen) == 0 ||
897 strncmp(p, "1", plen) == 0)
900 } else if (strncasecmp(p, "false", plen) == 0 ||
901 strncasecmp(p, "no", plen) == 0 ||
902 strncmp(p, "0", plen) == 0)
906 /* Not a recognized boolean string */
910 /* Write to output */
911 nbytes = sizeof(bhnd_nvram_bool_t);
913 *((bhnd_nvram_bool_t *)outp) = bval;
915 /* Provide required length */
917 if (limit < *olen && outp != NULL)
923 case BHND_NVRAM_TYPE_DATA: {
925 size_t plen, parsed_len;
928 /* Trim leading/trailing whitespace */
930 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
932 /* Check for EFI-style hexadecimal byte array string format.
933 * Must have a 'H' prefix */
934 if (plen < 1 || bhnd_nv_toupper(*p) != 'H')
937 /* Skip leading 'H' */
941 /* Parse the input string's two-char octets until the end
942 * of input is reached. The last octet may contain only
946 size_t byte_len = sizeof(byte);
948 /* Parse next two-character hex octet */
949 error = bhnd_nvram_parse_int(p, bhnd_nv_ummin(plen, 2),
950 16, &parsed_len, &byte, &byte_len, otype_base);
952 BHND_NV_DEBUG("error parsing '%.*s' as "
953 "integer: %d\n", BHND_NV_PRINT_WIDTH(plen),
959 /* Write to output */
961 *((uint8_t *)outp + nbytes) = byte;
969 /* Provide required length */
971 if (limit < *olen && outp != NULL)
977 case BHND_NVRAM_TYPE_UINT8:
978 case BHND_NVRAM_TYPE_UINT8_ARRAY:
979 case BHND_NVRAM_TYPE_UINT16:
980 case BHND_NVRAM_TYPE_UINT16_ARRAY:
981 case BHND_NVRAM_TYPE_UINT32:
982 case BHND_NVRAM_TYPE_UINT32_ARRAY:
983 case BHND_NVRAM_TYPE_UINT64:
984 case BHND_NVRAM_TYPE_UINT64_ARRAY:
985 case BHND_NVRAM_TYPE_INT8:
986 case BHND_NVRAM_TYPE_INT8_ARRAY:
987 case BHND_NVRAM_TYPE_INT16:
988 case BHND_NVRAM_TYPE_INT16_ARRAY:
989 case BHND_NVRAM_TYPE_INT32:
990 case BHND_NVRAM_TYPE_INT32_ARRAY:
991 case BHND_NVRAM_TYPE_INT64:
992 case BHND_NVRAM_TYPE_INT64_ARRAY: {
994 size_t plen, parsed_len;
997 /* Trim leading/trailing whitespace */
999 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
1001 /* Try to parse the integer value */
1002 error = bhnd_nvram_parse_int(p, plen, 0, &parsed_len, outp,
1005 BHND_NV_DEBUG("error parsing '%.*s' as integer: %d\n",
1006 BHND_NV_PRINT_WIDTH(plen), p, error);
1010 /* Do additional bytes remain unparsed? */
1011 if (plen != parsed_len) {
1012 BHND_NV_DEBUG("error parsing '%.*s' as a single "
1013 "integer value; trailing garbage '%.*s'\n",
1014 BHND_NV_PRINT_WIDTH(plen), p,
1015 BHND_NV_PRINT_WIDTH(plen-parsed_len), p+parsed_len);
1022 case BHND_NVRAM_TYPE_STRING:
1023 case BHND_NVRAM_TYPE_STRING_ARRAY:
1024 /* Copy out the string representation as-is */
1027 /* Need additional space for trailing NUL? */
1028 if (cstr_len == cstr_size)
1035 /* Verify required length */
1039 /* Copy and NUL terminate */
1040 strncpy(outp, cstr, cstr_len);
1041 *((char *)outp + cstr_len) = '\0';
1046 BHND_NV_PANIC("unknown type %s", bhnd_nvram_type_name(otype));
1050 * Standard integer encoding implementation.
1053 bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype,
1054 void *outp, size_t *olen, bhnd_nvram_type otype)
1056 bhnd_nvram_type otype_base;
1057 size_t limit, nbytes;
1058 bool itype_signed, otype_signed, otype_int;
1064 BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("non-integer type"));
1066 /* Determine output byte limit */
1072 /* Fetch output type info */
1073 otype_base = bhnd_nvram_base_type(otype);
1074 otype_int = bhnd_nvram_is_int_type(otype);
1075 otype_signed = bhnd_nvram_is_signed_type(otype_base);
1078 * Promote integer value to a common 64-bit representation.
1081 case BHND_NVRAM_TYPE_UINT8:
1082 if (ilen != sizeof(uint8_t))
1085 itype_signed = false;
1086 intv.u64 = *(const uint8_t *)inp;
1089 case BHND_NVRAM_TYPE_UINT16:
1090 if (ilen != sizeof(uint16_t))
1093 itype_signed = false;
1094 intv.u64 = *(const uint16_t *)inp;
1097 case BHND_NVRAM_TYPE_UINT32:
1098 if (ilen != sizeof(uint32_t))
1101 itype_signed = false;
1102 intv.u64 = *(const uint32_t *)inp;
1105 case BHND_NVRAM_TYPE_UINT64:
1106 if (ilen != sizeof(uint64_t))
1109 itype_signed = false;
1110 intv.u64 = *(const uint64_t *)inp;
1113 case BHND_NVRAM_TYPE_INT8:
1114 if (ilen != sizeof(int8_t))
1117 itype_signed = true;
1118 intv.i64 = *(const int8_t *)inp;
1121 case BHND_NVRAM_TYPE_INT16:
1122 if (ilen != sizeof(int16_t))
1125 itype_signed = true;
1126 intv.i64 = *(const int16_t *)inp;
1129 case BHND_NVRAM_TYPE_INT32:
1130 if (ilen != sizeof(int32_t))
1133 itype_signed = true;
1134 intv.i64 = *(const int32_t *)inp;
1137 case BHND_NVRAM_TYPE_INT64:
1138 if (ilen != sizeof(int32_t))
1141 itype_signed = true;
1142 intv.i64 = *(const int32_t *)inp;
1146 BHND_NV_PANIC("invalid type %d\n", itype);
1149 /* Perform signed/unsigned conversion */
1150 if (itype_signed && otype_int && !otype_signed) {
1152 /* Can't represent negative value */
1153 BHND_NV_LOG("cannot represent %" PRId64 " as %s\n",
1154 intv.i64, bhnd_nvram_type_name(otype));
1159 /* Convert to unsigned representation */
1160 intv.u64 = intv.i64;
1162 } else if (!itype_signed && otype_int && otype_signed) {
1163 /* Handle unsigned -> signed coercions */
1164 if (intv.u64 > INT64_MAX) {
1165 /* Can't represent positive value */
1166 BHND_NV_LOG("cannot represent %" PRIu64 " as %s\n",
1167 intv.u64, bhnd_nvram_type_name(otype));
1171 /* Convert to signed representation */
1172 intv.i64 = intv.u64;
1177 case BHND_NVRAM_TYPE_NULL:
1178 /* Cannot encode an integer value as NULL */
1181 case BHND_NVRAM_TYPE_BOOL: {
1182 bhnd_nvram_bool_t bval;
1184 if (intv.u64 == 0 || intv.u64 == 1) {
1187 /* Encoding as a bool would lose information */
1191 nbytes = sizeof(bhnd_nvram_bool_t);
1192 if (limit >= nbytes)
1193 *((bhnd_nvram_bool_t *)outp) = bval;
1198 case BHND_NVRAM_TYPE_CHAR:
1199 case BHND_NVRAM_TYPE_CHAR_ARRAY:
1200 case BHND_NVRAM_TYPE_DATA:
1201 case BHND_NVRAM_TYPE_UINT8:
1202 case BHND_NVRAM_TYPE_UINT8_ARRAY:
1203 if (intv.u64 > UINT8_MAX)
1206 nbytes = sizeof(uint8_t);
1207 if (limit >= nbytes)
1208 *((uint8_t *)outp) = (uint8_t)intv.u64;
1211 case BHND_NVRAM_TYPE_UINT16:
1212 case BHND_NVRAM_TYPE_UINT16_ARRAY:
1213 if (intv.u64 > UINT16_MAX)
1216 nbytes = sizeof(uint16_t);
1217 if (limit >= nbytes)
1218 *((uint16_t *)outp) = (uint16_t)intv.u64;
1221 case BHND_NVRAM_TYPE_UINT32:
1222 case BHND_NVRAM_TYPE_UINT32_ARRAY:
1223 if (intv.u64 > UINT32_MAX)
1226 nbytes = sizeof(uint32_t);
1227 if (limit >= nbytes)
1228 *((uint32_t *)outp) = (uint32_t)intv.u64;
1231 case BHND_NVRAM_TYPE_UINT64:
1232 case BHND_NVRAM_TYPE_UINT64_ARRAY:
1233 nbytes = sizeof(uint64_t);
1234 if (limit >= nbytes)
1235 *((uint64_t *)outp) = intv.u64;
1238 case BHND_NVRAM_TYPE_INT8:
1239 case BHND_NVRAM_TYPE_INT8_ARRAY:
1240 if (intv.i64 < INT8_MIN || intv.i64 > INT8_MAX)
1243 nbytes = sizeof(int8_t);
1244 if (limit >= nbytes)
1245 *((int8_t *)outp) = (int8_t)intv.i64;
1248 case BHND_NVRAM_TYPE_INT16:
1249 case BHND_NVRAM_TYPE_INT16_ARRAY:
1250 if (intv.i64 < INT16_MIN || intv.i64 > INT16_MAX)
1253 nbytes = sizeof(int16_t);
1254 if (limit >= nbytes)
1255 *((int16_t *)outp) = (int16_t)intv.i64;
1258 case BHND_NVRAM_TYPE_INT32:
1259 case BHND_NVRAM_TYPE_INT32_ARRAY:
1260 if (intv.i64 < INT32_MIN || intv.i64 > INT32_MAX)
1263 nbytes = sizeof(int32_t);
1264 if (limit >= nbytes)
1265 *((int32_t *)outp) = (int32_t)intv.i64;
1268 case BHND_NVRAM_TYPE_INT64:
1269 case BHND_NVRAM_TYPE_INT64_ARRAY:
1270 nbytes = sizeof(int64_t);
1271 if (limit >= nbytes)
1272 *((int64_t *)outp) = intv.i64;
1275 case BHND_NVRAM_TYPE_STRING:
1276 case BHND_NVRAM_TYPE_STRING_ARRAY: {
1279 /* Attempt to write the entry + NUL */
1281 len = snprintf(outp, limit, "%" PRId64, intv.i64);
1283 len = snprintf(outp, limit, "%" PRIu64, intv.u64);
1287 BHND_NV_LOG("snprintf() failed: %zd\n", len);
1291 /* Set total length to the formatted string length, plus
1298 BHND_NV_LOG("unknown type %s\n", bhnd_nvram_type_name(otype));
1302 /* Provide required length */
1304 if (limit < *olen) {
1315 * Encode the given @p value as @p otype, writing the result to @p outp.
1317 * @param value The value to be encoded.
1318 * @param[out] outp On success, the value will be written to this
1319 * buffer. This argment may be NULL if the value is
1321 * @param[in,out] olen The capacity of @p outp. On success, will be set
1322 * to the actual size of the requested value.
1323 * @param otype The data type to be written to @p outp.
1326 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
1327 * is too small to hold the encoded value.
1328 * @retval EFTYPE If value coercion from @p value to @p otype is
1330 * @retval ERANGE If value coercion would overflow (or underflow) the
1331 * a @p otype representation.
1334 bhnd_nvram_val_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
1335 bhnd_nvram_type otype)
1337 /* Prefer format implementation */
1338 if (value->fmt->op_encode != NULL)
1339 return (value->fmt->op_encode(value, outp, olen, otype));
1341 return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
1345 * Encode the given @p value's element as @p otype, writing the result to
1348 * @param inp The element to be be encoded. Must be a value
1349 * previously returned by bhnd_nvram_val_next()
1350 * or bhnd_nvram_val_elem().
1351 * @param ilen The size of @p inp, as returned by
1352 * bhnd_nvram_val_next() or bhnd_nvram_val_elem().
1353 * @param[out] outp On success, the value will be written to this
1354 * buffer. This argment may be NULL if the value is
1356 * @param[in,out] olen The capacity of @p outp. On success, will be set
1357 * to the actual size of the requested value.
1358 * @param otype The data type to be written to @p outp.
1361 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
1362 * is too small to hold the encoded value.
1363 * @retval EFTYPE If value coercion from @p value to @p otype is
1365 * @retval ERANGE If value coercion would overflow (or underflow) the
1366 * a @p otype representation.
1369 bhnd_nvram_val_encode_elem(bhnd_nvram_val *value, const void *inp,
1370 size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
1372 /* Prefer format implementation */
1373 if (value->fmt->op_encode_elem != NULL) {
1374 return (value->fmt->op_encode_elem(value, inp, ilen, outp,
1378 return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen, outp,
1383 * Return the type, size, and a pointer to the internal representation
1386 * @param value The value to be queried.
1387 * @param[out] olen Size of the returned data, in bytes.
1388 * @param[out] otype Data type.
1391 bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
1392 bhnd_nvram_type *otype)
1394 /* Provide type and length */
1395 *otype = value->data_type;
1396 *olen = value->data_len;
1398 switch (value->data_storage) {
1399 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
1400 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
1401 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
1402 /* Return a pointer to external storage */
1403 return (value->data.ptr);
1405 case BHND_NVRAM_VAL_DATA_INLINE:
1406 /* Return a pointer to inline storage */
1407 return (&value->data);
1409 case BHND_NVRAM_VAL_DATA_NONE:
1410 BHND_NV_PANIC("uninitialized value");
1413 BHND_NV_PANIC("unknown storage type: %d", value->data_storage);
1417 * Iterate over all array elements in @p value.
1419 * @param value The value to be iterated
1420 * @param prev A value pointer previously returned by
1421 * bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
1422 * or NULL to begin iteration at the first element.
1423 * @param[in,out] olen If @p prev is non-NULL, @p olen must be a
1424 * pointer to the length previously returned by
1425 * bhnd_nvram_val_next() or bhnd_nvram_val_elem().
1426 * On success, will be set to the next element's
1429 * @retval non-NULL A borrowed reference to the element data.
1430 * @retval NULL If the end of the element array is reached.
1433 bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *olen)
1435 /* Prefer the format implementation */
1436 if (value->fmt->op_next != NULL)
1437 return (value->fmt->op_next(value, prev, olen));
1439 return (bhnd_nvram_val_generic_next(value, prev, olen));
1443 * Return the value's data type.
1445 * @param value The value to be queried.
1448 bhnd_nvram_val_type(bhnd_nvram_val *value)
1450 return (value->data_type);
1454 * Return value's element data type.
1456 * @param value The value to be queried.
1459 bhnd_nvram_val_elem_type(bhnd_nvram_val *value)
1461 return (bhnd_nvram_base_type(value->data_type));
1465 * Return the total number of elements represented by @p value.
1468 bhnd_nvram_val_nelem(bhnd_nvram_val *value)
1471 bhnd_nvram_type type;
1475 /* Prefer format implementation */
1476 if (value->fmt->op_nelem != NULL)
1477 return (value->fmt->op_nelem(value));
1480 * If a custom op_next() is defined, bhnd_nvram_value_nelem() almost
1481 * certainly cannot produce a valid element count; it assumes a standard
1482 * data format that may not apply when custom iteration is required.
1484 * Instead, use bhnd_nvram_val_next() to parse the backing data and
1485 * produce a total count.
1487 if (value->fmt->op_next != NULL) {
1492 while ((next = bhnd_nvram_val_next(value, next, &len)) != NULL)
1498 /* Otherwise, compute the standard element count */
1499 bytes = bhnd_nvram_val_bytes(value, &len, &type);
1500 if ((error = bhnd_nvram_value_nelem(bytes, len, type, &nelem))) {
1501 /* Should always succeed */
1502 BHND_NV_PANIC("error calculating element count for type '%s' "
1503 "with length %zu: %d\n", bhnd_nvram_type_name(type), len,
1511 * Generic implementation of bhnd_nvram_val_op_encode(), compatible with
1512 * all supported NVRAM data types.
1515 bhnd_nvram_val_generic_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
1516 bhnd_nvram_type otype)
1519 bhnd_nvram_type itype;
1522 bhnd_nvram_type otype_base;
1523 size_t limit, nelem, nbytes;
1529 otype_base = bhnd_nvram_base_type(otype);
1530 inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
1533 * Normally, an array type is not universally representable as
1536 * As exceptions, we support conversion directly to/from:
1537 * - CHAR_ARRAY/STRING:
1538 * ->STRING Interpret the character array as a
1539 * non-NUL-terminated string.
1540 * ->CHAR_ARRAY Trim the trailing NUL from the string.
1542 #define BHND_NV_IS_ISO_CONV(_lhs, _rhs) \
1543 ((itype == BHND_NVRAM_TYPE_ ## _lhs && \
1544 otype == BHND_NVRAM_TYPE_ ## _rhs) || \
1545 (itype == BHND_NVRAM_TYPE_ ## _rhs && \
1546 otype == BHND_NVRAM_TYPE_ ## _lhs))
1548 if (BHND_NV_IS_ISO_CONV(CHAR_ARRAY, STRING)) {
1549 return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
1553 #undef BHND_NV_IS_ISO_CONV
1556 * If both input and output are non-array types, try to encode them
1557 * without performing element iteration.
1559 if (!bhnd_nvram_is_array_type(itype) &&
1560 !bhnd_nvram_is_array_type(otype))
1562 return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
1566 /* Determine output byte limit */
1572 /* Iterate over our array elements and encode as the requested
1575 while ((next = bhnd_nvram_val_next(value, next, &next_len))) {
1579 /* If the output type is not an array type, we can only encode
1582 if (nelem > 1 && !bhnd_nvram_is_array_type(otype)) {
1586 /* Determine output offset / limit */
1587 if (nbytes >= limit) {
1591 elem_nbytes = limit - nbytes;
1592 elem_outp = (uint8_t *)outp + nbytes;
1595 /* Attempt encode */
1596 error = bhnd_nvram_val_encode_elem(value, next, next_len,
1597 elem_outp, &elem_nbytes, otype_base);
1599 /* If encoding failed for any reason other than ENOMEM (which
1600 * we'll detect and report below), return immediately */
1601 if (error && error != ENOMEM)
1604 /* Add to total length */
1605 if (SIZE_MAX - nbytes < elem_nbytes)
1606 return (EFTYPE); /* would overflow size_t */
1608 nbytes += elem_nbytes;
1611 /* Provide the actual length */
1614 /* If no output was requested, nothing left to do */
1618 /* Otherwise, report a memory error if the output buffer was too
1627 * Generic implementation of bhnd_nvram_val_op_encode_elem(), compatible with
1628 * all supported NVRAM data types.
1631 bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
1632 size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
1634 bhnd_nvram_type itype;
1636 itype = bhnd_nvram_val_elem_type(value);
1638 case BHND_NVRAM_TYPE_NULL:
1639 return (bhnd_nvram_val_encode_null(inp, ilen, itype, outp, olen,
1642 case BHND_NVRAM_TYPE_DATA:
1643 return (bhnd_nvram_val_encode_data(inp, ilen, itype, outp,
1646 case BHND_NVRAM_TYPE_STRING:
1647 case BHND_NVRAM_TYPE_CHAR:
1648 return (bhnd_nvram_val_encode_string(inp, ilen, itype, outp,
1651 case BHND_NVRAM_TYPE_BOOL:
1652 return (bhnd_nvram_val_encode_bool(inp, ilen, itype, outp, olen,
1655 case BHND_NVRAM_TYPE_UINT8:
1656 case BHND_NVRAM_TYPE_UINT16:
1657 case BHND_NVRAM_TYPE_UINT32:
1658 case BHND_NVRAM_TYPE_UINT64:
1659 case BHND_NVRAM_TYPE_INT8:
1660 case BHND_NVRAM_TYPE_INT16:
1661 case BHND_NVRAM_TYPE_INT32:
1662 case BHND_NVRAM_TYPE_INT64:
1663 return (bhnd_nvram_val_encode_int(inp, ilen, itype, outp, olen,
1666 BHND_NV_PANIC("missing encode_elem() implementation");
1671 * Generic implementation of bhnd_nvram_val_op_next(), compatible with
1672 * all supported NVRAM data types.
1675 bhnd_nvram_val_generic_next(bhnd_nvram_val *value, const void *prev,
1679 bhnd_nvram_type itype;
1682 /* Iterate over the backing representation */
1683 inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
1684 return (bhnd_nvram_value_array_next(inp, ilen, itype, prev, olen));
1688 * Initialize the representation of @p value with @p ptr.
1690 * @param value The value to be initialized.
1691 * @param inp The external representation.
1692 * @param ilen The external representation length, in bytes.
1693 * @param itype The external representation's data type.
1694 * @param flags Value flags.
1696 * @retval 0 success.
1697 * @retval ENOMEM if allocation fails
1698 * @retval EFTYPE if @p itype is not an array type, and @p ilen is not
1699 * equal to the size of a single element of @p itype.
1700 * @retval EFAULT if @p ilen is not correctly aligned for elements of
1704 bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, size_t ilen,
1705 bhnd_nvram_type itype, uint32_t flags)
1710 BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1712 /* Validate alignment */
1713 if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
1716 /* Reference the external data */
1717 if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
1718 (flags & BHND_NVRAM_VAL_STATIC_DATA))
1720 if (flags & BHND_NVRAM_VAL_STATIC_DATA)
1721 value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
1723 value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
1725 value->data.ptr = inp;
1726 value->data_type = itype;
1727 value->data_len = ilen;
1731 /* Fetch reference to (or allocate) an appropriately sized buffer */
1732 bytes = bhnd_nvram_val_alloc_bytes(value, ilen, itype, flags);
1737 memcpy(bytes, inp, ilen);
1743 * Initialize the internal inline representation of @p value with a copy of
1744 * the data referenced by @p inp of @p itype.
1746 * If @p inp is NULL, @p itype and @p ilen will be validated, but no data will
1749 * @param value The value to be initialized.
1750 * @param inp The input data to be copied, or NULL to verify
1751 * that data of @p ilen and @p itype can be represented
1753 * @param ilen The size of the external buffer to be allocated.
1754 * @param itype The type of the external buffer to be allocated.
1757 * @retval ENOMEM if @p ilen is too large to be represented inline.
1758 * @retval EFAULT if @p ilen is not correctly aligned for elements of
1762 bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen,
1763 bhnd_nvram_type itype)
1765 BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1767 #define NV_STORE_INIT_INLINE() do { \
1768 value->data_len = ilen; \
1769 value->data_type = itype; \
1772 #define NV_STORE_INLINE(_type, _dest) do { \
1773 if (ilen != sizeof(_type)) \
1776 if (inp != NULL) { \
1777 value->data._dest[0] = *(const _type *)inp; \
1778 NV_STORE_INIT_INLINE(); \
1782 #define NV_COPY_ARRRAY_INLINE(_type, _dest) do { \
1783 if (ilen % sizeof(_type) != 0) \
1786 if (ilen > nitems(value->data. _dest)) \
1792 memcpy(&value->data._dest, inp, ilen); \
1793 if (inp != NULL) { \
1794 memcpy(&value->data._dest, inp, ilen); \
1795 NV_STORE_INIT_INLINE(); \
1799 /* Attempt to copy to inline storage */
1801 case BHND_NVRAM_TYPE_NULL:
1805 /* Nothing to copy */
1806 NV_STORE_INIT_INLINE();
1809 case BHND_NVRAM_TYPE_CHAR:
1810 NV_STORE_INLINE(uint8_t, ch);
1813 case BHND_NVRAM_TYPE_BOOL:
1814 NV_STORE_INLINE(bhnd_nvram_bool_t, b);
1817 case BHND_NVRAM_TYPE_UINT8:
1818 case BHND_NVRAM_TYPE_INT8:
1819 NV_STORE_INLINE(uint8_t, u8);
1822 case BHND_NVRAM_TYPE_UINT16:
1823 case BHND_NVRAM_TYPE_INT16:
1824 NV_STORE_INLINE(uint16_t, u16);
1827 case BHND_NVRAM_TYPE_UINT32:
1828 case BHND_NVRAM_TYPE_INT32:
1829 NV_STORE_INLINE(uint32_t, u32);
1832 case BHND_NVRAM_TYPE_UINT64:
1833 case BHND_NVRAM_TYPE_INT64:
1834 NV_STORE_INLINE(uint32_t, u32);
1837 case BHND_NVRAM_TYPE_CHAR_ARRAY:
1838 NV_COPY_ARRRAY_INLINE(uint8_t, ch);
1841 case BHND_NVRAM_TYPE_DATA:
1842 case BHND_NVRAM_TYPE_UINT8_ARRAY:
1843 case BHND_NVRAM_TYPE_INT8_ARRAY:
1844 NV_COPY_ARRRAY_INLINE(uint8_t, u8);
1847 case BHND_NVRAM_TYPE_UINT16_ARRAY:
1848 case BHND_NVRAM_TYPE_INT16_ARRAY:
1849 NV_COPY_ARRRAY_INLINE(uint16_t, u16);
1852 case BHND_NVRAM_TYPE_UINT32_ARRAY:
1853 case BHND_NVRAM_TYPE_INT32_ARRAY:
1854 NV_COPY_ARRRAY_INLINE(uint32_t, u32);
1857 case BHND_NVRAM_TYPE_UINT64_ARRAY:
1858 case BHND_NVRAM_TYPE_INT64_ARRAY:
1859 NV_COPY_ARRRAY_INLINE(uint64_t, u64);
1862 case BHND_NVRAM_TYPE_BOOL_ARRAY:
1863 NV_COPY_ARRRAY_INLINE(bhnd_nvram_bool_t, b);
1866 case BHND_NVRAM_TYPE_STRING:
1867 case BHND_NVRAM_TYPE_STRING_ARRAY:
1868 if (ilen > sizeof(value->data.ch))
1872 memcpy(&value->data.ch, inp, ilen);
1873 NV_STORE_INIT_INLINE();
1879 #undef NV_STORE_INIT_INLINE
1880 #undef NV_STORE_INLINE
1881 #undef NV_COPY_ARRRAY_INLINE
1883 BHND_NV_PANIC("unknown data type %d", itype);
1887 * Initialize the internal representation of @p value with a buffer allocation
1888 * of @p len and @p itype, returning a pointer to the allocated buffer.
1890 * If a buffer of @p len and @p itype can be represented inline, no
1891 * external buffer will be allocated, and instead a pointer to the inline
1892 * data representation will be returned.
1894 * @param value The value to be initialized.
1895 * @param ilen The size of the external buffer to be allocated.
1896 * @param itype The type of the external buffer to be allocated.
1897 * @param flags Value flags.
1899 * @retval non-null The newly allocated buffer.
1900 * @retval NULL If allocation failed.
1901 * @retval NULL If @p value is an externally allocated instance.
1904 bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
1905 bhnd_nvram_type itype, uint32_t flags)
1909 BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1911 /* Can we use inline storage? */
1912 if (bhnd_nvram_val_set_inline(value, NULL, ilen, itype) == 0) {
1913 BHND_NV_ASSERT(sizeof(value->data) >= ilen,
1914 ("ilen exceeds inline storage"));
1916 value->data_type = itype;
1917 value->data_len = ilen;
1918 value->data_storage = BHND_NVRAM_VAL_DATA_INLINE;
1919 return (&value->data);
1922 /* Is allocation permitted? */
1923 if (!(flags & BHND_NVRAM_VAL_DYNAMIC))
1926 /* Allocate external storage */
1927 if ((ptr = bhnd_nv_malloc(ilen)) == NULL)
1930 value->data.ptr = ptr;
1931 value->data_len = ilen;
1932 value->data_type = itype;
1933 value->data_storage = BHND_NVRAM_VAL_DATA_EXT_ALLOC;