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>
34 #include <sys/limits.h>
39 #include <sys/ctype.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/systm.h>
44 #include <machine/_inttypes.h>
56 #include "bhnd_nvram_private.h"
58 #include "bhnd_nvram_valuevar.h"
60 static int bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
61 const void *inp, size_t ilen, bhnd_nvram_type itype);
63 static void *bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
64 bhnd_nvram_type itype, uint32_t flags);
65 static int bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp,
66 size_t ilen, bhnd_nvram_type itype, uint32_t flags);
67 static int bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
68 const void *inp, size_t ilen, bhnd_nvram_type itype);
71 static int bhnd_nvram_val_encode_data(const void *inp, size_t ilen,
72 bhnd_nvram_type itype, void *outp, size_t *olen,
73 bhnd_nvram_type otype);
74 static int bhnd_nvram_val_encode_int(const void *inp, size_t ilen,
75 bhnd_nvram_type itype, void *outp, size_t *olen,
76 bhnd_nvram_type otype);
77 static int bhnd_nvram_val_encode_null(const void *inp, size_t ilen,
78 bhnd_nvram_type itype, void *outp, size_t *olen,
79 bhnd_nvram_type otype);
80 static int bhnd_nvram_val_encode_bool(const void *inp, size_t ilen,
81 bhnd_nvram_type itype, void *outp, size_t *olen,
82 bhnd_nvram_type otype);
83 static int bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
84 bhnd_nvram_type itype, void *outp, size_t *olen,
85 bhnd_nvram_type otype);
87 /** Initialize an empty value instance with @p _fmt, @p _storage, and
88 * an implicit callee-owned reference */
89 #define BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage) \
92 .val_storage = _storage, \
94 .data_storage = BHND_NVRAM_VAL_DATA_NONE, \
97 /** Assert that @p value's backing representation state has initialized
99 #define BHND_NVRAM_VAL_ASSERT_EMPTY(_value) \
101 value->data_storage == BHND_NVRAM_VAL_DATA_NONE && \
102 value->data_len == 0 && \
103 value->data.ptr == NULL, \
104 ("previously initialized value"))
106 /** Return true if BHND_NVRAM_VAL_BORROW_DATA or BHND_NVRAM_VAL_STATIC_DATA is
107 * set in @p _flags (e.g. we should attempt to directly reference external
109 #define BHND_NVRAM_VAL_EXTREF_BORROWED_DATA(_flags) \
110 (((_flags) & BHND_NVRAM_VAL_BORROW_DATA) || \
111 ((_flags) & BHND_NVRAM_VAL_STATIC_DATA))
113 /** Flags permitted when performing val-based initialization via
114 * bhnd_nvram_val_convert_init() or bhnd_nvram_val_convert_new() */
115 #define BHND_NVRAM_VALID_CONV_FLAGS \
116 (BHND_NVRAM_VAL_FIXED | \
117 BHND_NVRAM_VAL_DYNAMIC | \
118 BHND_NVRAM_VAL_COPY_DATA)
120 /** Returns true if @p _val must be copied in bhnd_nvram_val_copy(), false
121 * if its reference count may be safely incremented */
122 #define BHND_NVRAM_VAL_NEED_COPY(_val) \
123 ((_val)->val_storage == BHND_NVRAM_VAL_STORAGE_AUTO || \
124 (_val)->data_storage == BHND_NVRAM_VAL_DATA_EXT_WEAK)
126 volatile u_int refs; /**< reference count */
127 bhnd_nvram_val_storage val_storage; /**< value structure storage */
128 const bhnd_nvram_val_fmt *fmt; /**< value format */
129 bhnd_nvram_val_data_storage data_storage; /**< data storage */
130 bhnd_nvram_type data_type; /**< data type */
131 size_t data_len; /**< data size */
133 /* Shared NULL value instance */
134 bhnd_nvram_val bhnd_nvram_val_null = {
136 .val_storage = BHND_NVRAM_VAL_STORAGE_STATIC,
137 .fmt = &bhnd_nvram_val_null_fmt,
138 .data_storage = BHND_NVRAM_VAL_DATA_INLINE,
139 .data_type = BHND_NVRAM_TYPE_NULL,
144 * Return the human-readable name of @p fmt.
147 bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt *fmt)
153 * Return the default format for values of @p type.
155 const bhnd_nvram_val_fmt *
156 bhnd_nvram_val_default_fmt(bhnd_nvram_type type)
159 case BHND_NVRAM_TYPE_UINT8:
160 return (&bhnd_nvram_val_uint8_fmt);
161 case BHND_NVRAM_TYPE_UINT16:
162 return (&bhnd_nvram_val_uint16_fmt);
163 case BHND_NVRAM_TYPE_UINT32:
164 return (&bhnd_nvram_val_uint32_fmt);
165 case BHND_NVRAM_TYPE_UINT64:
166 return (&bhnd_nvram_val_uint64_fmt);
167 case BHND_NVRAM_TYPE_INT8:
168 return (&bhnd_nvram_val_int8_fmt);
169 case BHND_NVRAM_TYPE_INT16:
170 return (&bhnd_nvram_val_int16_fmt);
171 case BHND_NVRAM_TYPE_INT32:
172 return (&bhnd_nvram_val_int32_fmt);
173 case BHND_NVRAM_TYPE_INT64:
174 return (&bhnd_nvram_val_int64_fmt);
175 case BHND_NVRAM_TYPE_CHAR:
176 return (&bhnd_nvram_val_char_fmt);
177 case BHND_NVRAM_TYPE_STRING:
178 return (&bhnd_nvram_val_string_fmt);
179 case BHND_NVRAM_TYPE_BOOL:
180 return (&bhnd_nvram_val_bool_fmt);
181 case BHND_NVRAM_TYPE_NULL:
182 return (&bhnd_nvram_val_null_fmt);
183 case BHND_NVRAM_TYPE_DATA:
184 return (&bhnd_nvram_val_data_fmt);
185 case BHND_NVRAM_TYPE_UINT8_ARRAY:
186 return (&bhnd_nvram_val_uint8_array_fmt);
187 case BHND_NVRAM_TYPE_UINT16_ARRAY:
188 return (&bhnd_nvram_val_uint16_array_fmt);
189 case BHND_NVRAM_TYPE_UINT32_ARRAY:
190 return (&bhnd_nvram_val_uint32_array_fmt);
191 case BHND_NVRAM_TYPE_UINT64_ARRAY:
192 return (&bhnd_nvram_val_uint64_array_fmt);
193 case BHND_NVRAM_TYPE_INT8_ARRAY:
194 return (&bhnd_nvram_val_int8_array_fmt);
195 case BHND_NVRAM_TYPE_INT16_ARRAY:
196 return (&bhnd_nvram_val_int16_array_fmt);
197 case BHND_NVRAM_TYPE_INT32_ARRAY:
198 return (&bhnd_nvram_val_int32_array_fmt);
199 case BHND_NVRAM_TYPE_INT64_ARRAY:
200 return (&bhnd_nvram_val_int64_array_fmt);
201 case BHND_NVRAM_TYPE_CHAR_ARRAY:
202 return (&bhnd_nvram_val_char_array_fmt);
203 case BHND_NVRAM_TYPE_STRING_ARRAY:
204 return (&bhnd_nvram_val_string_array_fmt);
205 case BHND_NVRAM_TYPE_BOOL_ARRAY:
206 return (&bhnd_nvram_val_bool_array_fmt);
210 BHND_NV_PANIC("bhnd nvram type %u unknown", type);
214 * Determine whether @p fmt (or new format delegated to by @p fmt) is
215 * capable of direct initialization from buffer @p inp.
217 * @param[in,out] fmt Indirect pointer to the NVRAM value format. If
218 * the format instance cannot handle the data type
219 * directly, it may delegate to a new format
220 * instance. On success, this parameter will be
221 * set to the format that should be used when
222 * performing initialization from @p inp.
223 * @param inp Input data.
224 * @param ilen Input data length.
225 * @param itype Input data type.
227 * @retval 0 If initialization from @p inp is supported.
228 * @retval EFTYPE If initialization from @p inp is unsupported.
229 * @retval EFAULT if @p ilen is not correctly aligned for elements of
233 bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
234 size_t ilen, bhnd_nvram_type itype)
236 const bhnd_nvram_val_fmt *ofmt, *nfmt;
241 /* Validate alignment */
242 if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
245 /* If the format does not provide a filter function, it only supports
246 * direct initialization from its native type */
247 if (ofmt->op_filter == NULL) {
248 if (itype == ofmt->native_type)
254 /* Use the filter function to determine whether direct initialization
255 * from itype is permitted */
256 error = ofmt->op_filter(&nfmt, inp, ilen, itype);
260 /* Retry filter with new format? */
262 error = bhnd_nvram_val_fmt_filter(&nfmt, inp, ilen, itype);
266 /* Success -- provide delegated format to caller */
270 /* Value can be initialized with provided format and input type */
274 /* Common initialization support for bhnd_nvram_val_init() and
275 * bhnd_nvram_val_new() */
277 bhnd_nvram_val_init_common(bhnd_nvram_val *value,
278 bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
279 const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
282 bhnd_nvram_type otype;
286 /* If the value format is unspecified, we use the default format
287 * for the input data type */
289 fmt = bhnd_nvram_val_default_fmt(itype);
291 /* Determine expected data type, and allow the format to delegate to
292 * a new format instance */
293 if ((error = bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype))) {
294 /* Direct initialization from the provided input type is
295 * not supported; alue must be initialized with the format's
297 otype = fmt->native_type;
299 /* Value can be initialized with provided input type */
303 /* Initialize value instance */
304 *value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
306 /* If input data already in native format, init directly. */
307 if (otype == itype) {
308 error = bhnd_nvram_val_set(value, inp, ilen, itype, flags);
315 /* Determine size when encoded in native format */
316 error = bhnd_nvram_value_coerce(inp, ilen, itype, NULL, &olen, otype);
320 /* Fetch reference to (or allocate) an appropriately sized buffer */
321 outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
326 error = bhnd_nvram_value_coerce(inp, ilen, itype, outp, &olen, otype);
334 * Initialize an externally allocated instance of @p value with @p fmt from the
335 * given @p inp buffer of @p itype and @p ilen.
337 * On success, the caller owns a reference to @p value, and is responsible for
338 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
340 * @param value The externally allocated value instance to be
342 * @param fmt The value's format, or NULL to use the default format
344 * @param inp Input buffer.
345 * @param ilen Input buffer length.
346 * @param itype Input buffer type.
347 * @param flags Value flags (see BHND_NVRAM_VAL_*).
350 * @retval ENOMEM If allocation fails.
351 * @retval EFTYPE If @p fmt initialization from @p itype is unsupported.
352 * @retval EFAULT if @p ilen is not correctly aligned for elements of
354 * @retval ERANGE If value coercion would overflow (or underflow) the
355 * @p fmt representation.
358 bhnd_nvram_val_init(bhnd_nvram_val *value, const bhnd_nvram_val_fmt *fmt,
359 const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
363 error = bhnd_nvram_val_init_common(value, BHND_NVRAM_VAL_STORAGE_AUTO,
364 fmt, inp, ilen, itype, flags);
366 bhnd_nvram_val_release(value);
372 * Allocate a value instance with @p fmt, and attempt to initialize its internal
373 * representation from the given @p inp buffer of @p itype and @p ilen.
375 * On success, the caller owns a reference to @p value, and is responsible for
376 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
378 * @param[out] value On success, the allocated value instance.
379 * @param fmt The value's format, or NULL to use the default format
381 * @param inp Input buffer.
382 * @param ilen Input buffer length.
383 * @param itype Input buffer type.
384 * @param flags Value flags (see BHND_NVRAM_VAL_*).
387 * @retval ENOMEM If allocation fails.
388 * @retval EFTYPE If @p fmt initialization from @p itype is unsupported.
389 * @retval EFAULT if @p ilen is not correctly aligned for elements of
391 * @retval ERANGE If value coercion would overflow (or underflow) the
392 * @p fmt representation.
395 bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
396 const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
400 /* Allocate new instance */
401 if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
404 /* Perform common initialization. */
405 error = bhnd_nvram_val_init_common(*value,
406 BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, inp, ilen, itype, flags);
408 /* Will also free() the value allocation */
409 bhnd_nvram_val_release(*value);
416 /* Common initialization support for bhnd_nvram_val_convert_init() and
417 * bhnd_nvram_val_convert_new() */
419 bhnd_nvram_val_convert_common(bhnd_nvram_val *value,
420 bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
421 bhnd_nvram_val *src, uint32_t flags)
425 bhnd_nvram_type itype, otype;
429 /* Determine whether direct initialization from the source value's
430 * existing data type is supported by the new format */
431 inp = bhnd_nvram_val_bytes(src, &ilen, &itype);
432 if (bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype) == 0) {
433 /* Adjust value flags based on the source data storage */
434 switch (src->data_storage) {
435 case BHND_NVRAM_VAL_DATA_NONE:
436 case BHND_NVRAM_VAL_DATA_INLINE:
437 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
438 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
441 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
442 /* If the source data has static storage duration,
443 * we should apply that transitively */
444 if (flags & BHND_NVRAM_VAL_BORROW_DATA)
445 flags |= BHND_NVRAM_VAL_STATIC_DATA;
450 /* Delegate to standard initialization */
451 return (bhnd_nvram_val_init_common(value, val_storage, fmt, inp,
452 ilen, itype, flags));
455 /* Value must be initialized with the format's native type */
456 otype = fmt->native_type;
458 /* Initialize value instance */
459 *value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
461 /* Determine size when encoded in native format */
462 if ((error = bhnd_nvram_val_encode(src, NULL, &olen, otype)))
465 /* Fetch reference to (or allocate) an appropriately sized buffer */
466 outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
471 if ((error = bhnd_nvram_val_encode(src, outp, &olen, otype)))
478 * Initialize an externally allocated instance of @p value with @p fmt, and
479 * attempt to initialize its internal representation from the given @p src
482 * On success, the caller owns a reference to @p value, and is responsible for
483 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
485 * @param value The externally allocated value instance to be
487 * @param fmt The value's format.
488 * @param src Input value to be converted.
489 * @param flags Value flags (see BHND_NVRAM_VAL_*).
492 * @retval ENOMEM If allocation fails.
493 * @retval EFTYPE If @p fmt initialization from @p src is unsupported.
494 * @retval EFAULT if @p ilen is not correctly aligned for elements of
496 * @retval ERANGE If value coercion of @p src would overflow
497 * (or underflow) the @p fmt representation.
500 bhnd_nvram_val_convert_init(bhnd_nvram_val *value,
501 const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
505 error = bhnd_nvram_val_convert_common(value,
506 BHND_NVRAM_VAL_STORAGE_AUTO, fmt, src, flags);
508 bhnd_nvram_val_release(value);
514 * Allocate a value instance with @p fmt, and attempt to initialize its internal
515 * representation from the given @p src value.
517 * On success, the caller owns a reference to @p value, and is responsible for
518 * freeing any resources allocated for @p value via bhnd_nvram_val_release().
520 * @param[out] value On success, the allocated value instance.
521 * @param fmt The value's format.
522 * @param src Input value to be converted.
523 * @param flags Value flags (see BHND_NVRAM_VAL_*).
526 * @retval ENOMEM If allocation fails.
527 * @retval EFTYPE If @p fmt initialization from @p src is unsupported.
528 * @retval EFAULT if @p ilen is not correctly aligned for elements of
530 * @retval ERANGE If value coercion of @p src would overflow
531 * (or underflow) the @p fmt representation.
534 bhnd_nvram_val_convert_new(bhnd_nvram_val **value,
535 const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
539 /* Allocate new instance */
540 if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
543 /* Perform common initialization. */
544 error = bhnd_nvram_val_convert_common(*value,
545 BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, src, flags);
547 /* Will also free() the value allocation */
548 bhnd_nvram_val_release(*value);
555 * Copy or retain a reference to @p value.
557 * On success, the caller is responsible for freeing the result via
558 * bhnd_nvram_val_release().
560 * @param value The value to be copied (or retained).
562 * @retval bhnd_nvram_val if @p value was successfully copied or retained.
563 * @retval NULL if allocation failed.
566 bhnd_nvram_val_copy(bhnd_nvram_val *value)
568 bhnd_nvram_val *result;
570 bhnd_nvram_type type;
575 switch (value->val_storage) {
576 case BHND_NVRAM_VAL_STORAGE_STATIC:
577 /* If static, can return as-is */
580 case BHND_NVRAM_VAL_STORAGE_DYNAMIC:
581 if (!BHND_NVRAM_VAL_NEED_COPY(value)) {
582 refcount_acquire(&value->refs);
586 /* Perform copy below */
589 case BHND_NVRAM_VAL_STORAGE_AUTO:
590 BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
591 "active refcount (%u)", value->refs));
593 /* Perform copy below */
598 /* Compute the new value's flags based on the source value */
599 switch (value->data_storage) {
600 case BHND_NVRAM_VAL_DATA_NONE:
601 case BHND_NVRAM_VAL_DATA_INLINE:
602 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
603 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
604 /* Copy the source data and permit additional allocation if the
605 * value cannot be represented inline */
606 flags = BHND_NVRAM_VAL_COPY_DATA|BHND_NVRAM_VAL_DYNAMIC;
608 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
609 flags = BHND_NVRAM_VAL_STATIC_DATA;
612 BHND_NV_PANIC("invalid storage type: %d", value->data_storage);
615 /* Allocate new value copy */
616 bytes = bhnd_nvram_val_bytes(value, &len, &type);
617 error = bhnd_nvram_val_new(&result, value->fmt, bytes, len, type,
620 BHND_NV_LOG("copy failed: %d", error);
628 * Release a reference to @p value.
630 * If this is the last reference, all associated resources will be freed.
632 * @param value The value to be released.
635 bhnd_nvram_val_release(bhnd_nvram_val *value)
637 BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
639 /* Skip if value is static */
640 if (value->val_storage == BHND_NVRAM_VAL_STORAGE_STATIC)
644 if (!refcount_release(&value->refs))
647 /* Free allocated external representation data */
648 switch (value->data_storage) {
649 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
650 bhnd_nv_free(__DECONST(void *, value->data.ptr));
652 case BHND_NVRAM_VAL_DATA_NONE:
653 case BHND_NVRAM_VAL_DATA_INLINE:
654 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
655 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
656 /* Nothing to free */
660 /* Free instance if dynamically allocated */
661 if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
666 * Standard BHND_NVRAM_TYPE_NULL encoding implementation.
669 bhnd_nvram_val_encode_null(const void *inp, size_t ilen, bhnd_nvram_type itype,
670 void *outp, size_t *olen, bhnd_nvram_type otype)
672 size_t limit, nbytes;
674 BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_NULL,
675 ("unsupported type: %d", itype));
677 /* Determine output byte limit */
685 /* Write to output */
687 case BHND_NVRAM_TYPE_NULL:
688 /* Can be directly encoded as a zero-length NULL value */
692 /* Not representable */
696 /* Provide required length */
709 * Standard BHND_NVRAM_TYPE_BOOL encoding implementation.
712 bhnd_nvram_val_encode_bool(const void *inp, size_t ilen, bhnd_nvram_type itype,
713 void *outp, size_t *olen, bhnd_nvram_type otype)
715 bhnd_nvram_bool_t bval;
716 size_t limit, nbytes, nelem;
719 BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_BOOL,
720 ("unsupported type: %d", itype));
722 /* Determine output byte limit */
728 /* Must be exactly one element in input */
729 if ((error = bhnd_nvram_value_nelem(inp, ilen, itype, &nelem)))
735 /* Fetch (and normalize) boolean value */
736 bval = (*(const bhnd_nvram_bool_t *)inp != 0) ? true : false;
738 /* Write to output */
740 case BHND_NVRAM_TYPE_NULL:
741 /* False can be directly encoded as a zero-length NULL value */
748 case BHND_NVRAM_TYPE_STRING:
749 case BHND_NVRAM_TYPE_STRING_ARRAY: {
750 /* Can encode as "true" or "false" */
751 const char *str = bval ? "true" : "false";
753 nbytes = strlen(str) + 1;
761 /* If output type is an integer, we can delegate to standard
762 * integer encoding to encode as zero or one. */
763 if (bhnd_nvram_is_int_type(otype)) {
764 uint8_t ival = bval ? 1 : 0;
766 return (bhnd_nvram_val_encode_int(&ival, sizeof(ival),
767 BHND_NVRAM_TYPE_UINT8, outp, olen, otype));
770 /* Otherwise not representable */
774 /* Provide required length */
787 * Standard BHND_NVRAM_TYPE_DATA encoding implementation.
790 bhnd_nvram_val_encode_data(const void *inp, size_t ilen, bhnd_nvram_type itype,
791 void *outp, size_t *olen, bhnd_nvram_type otype)
793 BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_DATA,
794 ("unsupported type: %d", itype));
796 /* Write to output */
798 case BHND_NVRAM_TYPE_STRING:
799 case BHND_NVRAM_TYPE_STRING_ARRAY:
800 /* If encoding as a string, produce an EFI-style hexadecimal
801 * byte array (HF1F...) by interpreting the octet string
802 * as an array of uint8 values */
803 return (bhnd_nvram_value_printf("H%[]02hhX", inp, ilen,
804 BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, ""));
807 /* Fall back on direct interpretation as an array of 8-bit
809 return (bhnd_nvram_value_coerce(inp, ilen,
810 BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, otype));
816 * Standard string/char array/char encoding implementation.
818 * Input type must be one of:
819 * - BHND_NVRAM_TYPE_STRING
820 * - BHND_NVRAM_TYPE_CHAR
821 * - BHND_NVRAM_TYPE_CHAR_ARRAY
824 bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
825 bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype)
828 bhnd_nvram_type otype_base;
829 size_t cstr_size, cstr_len;
830 size_t limit, nbytes;
833 itype == BHND_NVRAM_TYPE_STRING ||
834 itype == BHND_NVRAM_TYPE_CHAR ||
835 itype == BHND_NVRAM_TYPE_CHAR_ARRAY,
836 ("unsupported type: %d", itype));
841 otype_base = bhnd_nvram_base_type(otype);
843 /* Determine output byte limit */
849 /* Determine string length, minus trailing NUL (if any) */
850 cstr_len = strnlen(cstr, cstr_size);
852 /* Parse the string data and write to output */
854 case BHND_NVRAM_TYPE_NULL:
855 /* Only an empty string may be represented as a NULL value */
862 case BHND_NVRAM_TYPE_CHAR:
863 case BHND_NVRAM_TYPE_CHAR_ARRAY:
864 /* String must contain exactly 1 non-terminating-NUL character
865 * to be represented as a single char */
866 if (!bhnd_nvram_is_array_type(otype)) {
871 /* Copy out the characters directly (excluding trailing NUL) */
872 for (size_t i = 0; i < cstr_len; i++) {
874 *((uint8_t *)outp + nbytes) = cstr[i];
878 /* Provide required length */
880 if (limit < *olen && outp != NULL)
885 case BHND_NVRAM_TYPE_BOOL:
886 case BHND_NVRAM_TYPE_BOOL_ARRAY: {
889 bhnd_nvram_bool_t bval;
891 /* Trim leading/trailing whitespace */
893 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
895 /* Parse string representation */
896 if (strncasecmp(p, "true", plen) == 0 ||
897 strncasecmp(p, "yes", plen) == 0 ||
898 strncmp(p, "1", plen) == 0)
901 } else if (strncasecmp(p, "false", plen) == 0 ||
902 strncasecmp(p, "no", plen) == 0 ||
903 strncmp(p, "0", plen) == 0)
907 /* Not a recognized boolean string */
911 /* Write to output */
912 nbytes = sizeof(bhnd_nvram_bool_t);
914 *((bhnd_nvram_bool_t *)outp) = bval;
916 /* Provide required length */
918 if (limit < *olen && outp != NULL)
924 case BHND_NVRAM_TYPE_DATA: {
926 size_t plen, parsed_len;
929 /* Trim leading/trailing whitespace */
931 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
933 /* Check for EFI-style hexadecimal byte array string format.
934 * Must have a 'H' prefix */
935 if (plen < 1 || bhnd_nv_toupper(*p) != 'H')
938 /* Skip leading 'H' */
942 /* Parse the input string's two-char octets until the end
943 * of input is reached. The last octet may contain only
947 size_t byte_len = sizeof(byte);
949 /* Parse next two-character hex octet */
950 error = bhnd_nvram_parse_int(p, bhnd_nv_ummin(plen, 2),
951 16, &parsed_len, &byte, &byte_len, otype_base);
953 BHND_NV_DEBUG("error parsing '%.*s' as "
954 "integer: %d\n", BHND_NV_PRINT_WIDTH(plen),
960 /* Write to output */
962 *((uint8_t *)outp + nbytes) = byte;
970 /* Provide required length */
972 if (limit < *olen && outp != NULL)
978 case BHND_NVRAM_TYPE_UINT8:
979 case BHND_NVRAM_TYPE_UINT8_ARRAY:
980 case BHND_NVRAM_TYPE_UINT16:
981 case BHND_NVRAM_TYPE_UINT16_ARRAY:
982 case BHND_NVRAM_TYPE_UINT32:
983 case BHND_NVRAM_TYPE_UINT32_ARRAY:
984 case BHND_NVRAM_TYPE_UINT64:
985 case BHND_NVRAM_TYPE_UINT64_ARRAY:
986 case BHND_NVRAM_TYPE_INT8:
987 case BHND_NVRAM_TYPE_INT8_ARRAY:
988 case BHND_NVRAM_TYPE_INT16:
989 case BHND_NVRAM_TYPE_INT16_ARRAY:
990 case BHND_NVRAM_TYPE_INT32:
991 case BHND_NVRAM_TYPE_INT32_ARRAY:
992 case BHND_NVRAM_TYPE_INT64:
993 case BHND_NVRAM_TYPE_INT64_ARRAY: {
995 size_t plen, parsed_len;
998 /* Trim leading/trailing whitespace */
1000 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
1002 /* Try to parse the integer value */
1003 error = bhnd_nvram_parse_int(p, plen, 0, &parsed_len, outp,
1006 BHND_NV_DEBUG("error parsing '%.*s' as integer: %d\n",
1007 BHND_NV_PRINT_WIDTH(plen), p, error);
1011 /* Do additional bytes remain unparsed? */
1012 if (plen != parsed_len) {
1013 BHND_NV_DEBUG("error parsing '%.*s' as a single "
1014 "integer value; trailing garbage '%.*s'\n",
1015 BHND_NV_PRINT_WIDTH(plen), p,
1016 BHND_NV_PRINT_WIDTH(plen-parsed_len), p+parsed_len);
1023 case BHND_NVRAM_TYPE_STRING:
1024 case BHND_NVRAM_TYPE_STRING_ARRAY:
1025 /* Copy out the string representation as-is */
1028 /* Need additional space for trailing NUL? */
1029 if (cstr_len == cstr_size)
1036 /* Verify required length */
1040 /* Copy and NUL terminate */
1041 strncpy(outp, cstr, cstr_len);
1042 *((char *)outp + cstr_len) = '\0';
1047 BHND_NV_PANIC("unknown type %s", bhnd_nvram_type_name(otype));
1051 * Standard integer encoding implementation.
1054 bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype,
1055 void *outp, size_t *olen, bhnd_nvram_type otype)
1057 bhnd_nvram_type otype_base;
1058 size_t limit, nbytes;
1059 bool itype_signed, otype_signed, otype_int;
1065 BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("non-integer type"));
1067 /* Determine output byte limit */
1073 /* Fetch output type info */
1074 otype_base = bhnd_nvram_base_type(otype);
1075 otype_int = bhnd_nvram_is_int_type(otype);
1076 otype_signed = bhnd_nvram_is_signed_type(otype_base);
1079 * Promote integer value to a common 64-bit representation.
1082 case BHND_NVRAM_TYPE_UINT8:
1083 if (ilen != sizeof(uint8_t))
1086 itype_signed = false;
1087 intv.u64 = *(const uint8_t *)inp;
1090 case BHND_NVRAM_TYPE_UINT16:
1091 if (ilen != sizeof(uint16_t))
1094 itype_signed = false;
1095 intv.u64 = *(const uint16_t *)inp;
1098 case BHND_NVRAM_TYPE_UINT32:
1099 if (ilen != sizeof(uint32_t))
1102 itype_signed = false;
1103 intv.u64 = *(const uint32_t *)inp;
1106 case BHND_NVRAM_TYPE_UINT64:
1107 if (ilen != sizeof(uint64_t))
1110 itype_signed = false;
1111 intv.u64 = *(const uint64_t *)inp;
1114 case BHND_NVRAM_TYPE_INT8:
1115 if (ilen != sizeof(int8_t))
1118 itype_signed = true;
1119 intv.i64 = *(const int8_t *)inp;
1122 case BHND_NVRAM_TYPE_INT16:
1123 if (ilen != sizeof(int16_t))
1126 itype_signed = true;
1127 intv.i64 = *(const int16_t *)inp;
1130 case BHND_NVRAM_TYPE_INT32:
1131 if (ilen != sizeof(int32_t))
1134 itype_signed = true;
1135 intv.i64 = *(const int32_t *)inp;
1138 case BHND_NVRAM_TYPE_INT64:
1139 if (ilen != sizeof(int32_t))
1142 itype_signed = true;
1143 intv.i64 = *(const int32_t *)inp;
1147 BHND_NV_PANIC("invalid type %d\n", itype);
1150 /* Perform signed/unsigned conversion */
1151 if (itype_signed && otype_int && !otype_signed) {
1153 /* Can't represent negative value */
1154 BHND_NV_LOG("cannot represent %" PRId64 " as %s\n",
1155 intv.i64, bhnd_nvram_type_name(otype));
1160 /* Convert to unsigned representation */
1161 intv.u64 = intv.i64;
1163 } else if (!itype_signed && otype_int && otype_signed) {
1164 /* Handle unsigned -> signed coercions */
1165 if (intv.u64 > INT64_MAX) {
1166 /* Can't represent positive value */
1167 BHND_NV_LOG("cannot represent %" PRIu64 " as %s\n",
1168 intv.u64, bhnd_nvram_type_name(otype));
1172 /* Convert to signed representation */
1173 intv.i64 = intv.u64;
1178 case BHND_NVRAM_TYPE_NULL:
1179 /* Cannot encode an integer value as NULL */
1182 case BHND_NVRAM_TYPE_BOOL: {
1183 bhnd_nvram_bool_t bval;
1185 if (intv.u64 == 0 || intv.u64 == 1) {
1188 /* Encoding as a bool would lose information */
1192 nbytes = sizeof(bhnd_nvram_bool_t);
1193 if (limit >= nbytes)
1194 *((bhnd_nvram_bool_t *)outp) = bval;
1199 case BHND_NVRAM_TYPE_CHAR:
1200 case BHND_NVRAM_TYPE_CHAR_ARRAY:
1201 case BHND_NVRAM_TYPE_DATA:
1202 case BHND_NVRAM_TYPE_UINT8:
1203 case BHND_NVRAM_TYPE_UINT8_ARRAY:
1204 if (intv.u64 > UINT8_MAX)
1207 nbytes = sizeof(uint8_t);
1208 if (limit >= nbytes)
1209 *((uint8_t *)outp) = (uint8_t)intv.u64;
1212 case BHND_NVRAM_TYPE_UINT16:
1213 case BHND_NVRAM_TYPE_UINT16_ARRAY:
1214 if (intv.u64 > UINT16_MAX)
1217 nbytes = sizeof(uint16_t);
1218 if (limit >= nbytes)
1219 *((uint16_t *)outp) = (uint16_t)intv.u64;
1222 case BHND_NVRAM_TYPE_UINT32:
1223 case BHND_NVRAM_TYPE_UINT32_ARRAY:
1224 if (intv.u64 > UINT32_MAX)
1227 nbytes = sizeof(uint32_t);
1228 if (limit >= nbytes)
1229 *((uint32_t *)outp) = (uint32_t)intv.u64;
1232 case BHND_NVRAM_TYPE_UINT64:
1233 case BHND_NVRAM_TYPE_UINT64_ARRAY:
1234 nbytes = sizeof(uint64_t);
1235 if (limit >= nbytes)
1236 *((uint64_t *)outp) = intv.u64;
1239 case BHND_NVRAM_TYPE_INT8:
1240 case BHND_NVRAM_TYPE_INT8_ARRAY:
1241 if (intv.i64 < INT8_MIN || intv.i64 > INT8_MAX)
1244 nbytes = sizeof(int8_t);
1245 if (limit >= nbytes)
1246 *((int8_t *)outp) = (int8_t)intv.i64;
1249 case BHND_NVRAM_TYPE_INT16:
1250 case BHND_NVRAM_TYPE_INT16_ARRAY:
1251 if (intv.i64 < INT16_MIN || intv.i64 > INT16_MAX)
1254 nbytes = sizeof(int16_t);
1255 if (limit >= nbytes)
1256 *((int16_t *)outp) = (int16_t)intv.i64;
1259 case BHND_NVRAM_TYPE_INT32:
1260 case BHND_NVRAM_TYPE_INT32_ARRAY:
1261 if (intv.i64 < INT32_MIN || intv.i64 > INT32_MAX)
1264 nbytes = sizeof(int32_t);
1265 if (limit >= nbytes)
1266 *((int32_t *)outp) = (int32_t)intv.i64;
1269 case BHND_NVRAM_TYPE_INT64:
1270 case BHND_NVRAM_TYPE_INT64_ARRAY:
1271 nbytes = sizeof(int64_t);
1272 if (limit >= nbytes)
1273 *((int64_t *)outp) = intv.i64;
1276 case BHND_NVRAM_TYPE_STRING:
1277 case BHND_NVRAM_TYPE_STRING_ARRAY: {
1280 /* Attempt to write the entry + NUL */
1282 len = snprintf(outp, limit, "%" PRId64, intv.i64);
1284 len = snprintf(outp, limit, "%" PRIu64, intv.u64);
1288 BHND_NV_LOG("snprintf() failed: %zd\n", len);
1292 /* Set total length to the formatted string length, plus
1299 BHND_NV_LOG("unknown type %s\n", bhnd_nvram_type_name(otype));
1303 /* Provide required length */
1305 if (limit < *olen) {
1316 * Encode the given @p value as @p otype, writing the result to @p outp.
1318 * @param value The value to be encoded.
1319 * @param[out] outp On success, the value will be written to this
1320 * buffer. This argment may be NULL if the value is
1322 * @param[in,out] olen The capacity of @p outp. On success, will be set
1323 * to the actual size of the requested value.
1324 * @param otype The data type to be written to @p outp.
1327 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
1328 * is too small to hold the encoded value.
1329 * @retval EFTYPE If value coercion from @p value to @p otype is
1331 * @retval ERANGE If value coercion would overflow (or underflow) the
1332 * a @p otype representation.
1335 bhnd_nvram_val_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
1336 bhnd_nvram_type otype)
1338 /* Prefer format implementation */
1339 if (value->fmt->op_encode != NULL)
1340 return (value->fmt->op_encode(value, outp, olen, otype));
1342 return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
1346 * Encode the given @p value's element as @p otype, writing the result to
1349 * @param inp The element to be be encoded. Must be a value
1350 * previously returned by bhnd_nvram_val_next()
1351 * or bhnd_nvram_val_elem().
1352 * @param ilen The size of @p inp, as returned by
1353 * bhnd_nvram_val_next() or bhnd_nvram_val_elem().
1354 * @param[out] outp On success, the value will be written to this
1355 * buffer. This argment may be NULL if the value is
1357 * @param[in,out] olen The capacity of @p outp. On success, will be set
1358 * to the actual size of the requested value.
1359 * @param otype The data type to be written to @p outp.
1362 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
1363 * is too small to hold the encoded value.
1364 * @retval EFTYPE If value coercion from @p value to @p otype is
1366 * @retval ERANGE If value coercion would overflow (or underflow) the
1367 * a @p otype representation.
1370 bhnd_nvram_val_encode_elem(bhnd_nvram_val *value, const void *inp,
1371 size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
1373 /* Prefer format implementation */
1374 if (value->fmt->op_encode_elem != NULL) {
1375 return (value->fmt->op_encode_elem(value, inp, ilen, outp,
1379 return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen, outp,
1384 * Return the type, size, and a pointer to the internal representation
1387 * @param value The value to be queried.
1388 * @param[out] olen Size of the returned data, in bytes.
1389 * @param[out] otype Data type.
1392 bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
1393 bhnd_nvram_type *otype)
1395 /* Provide type and length */
1396 *otype = value->data_type;
1397 *olen = value->data_len;
1399 switch (value->data_storage) {
1400 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
1401 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
1402 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
1403 /* Return a pointer to external storage */
1404 return (value->data.ptr);
1406 case BHND_NVRAM_VAL_DATA_INLINE:
1407 /* Return a pointer to inline storage */
1408 return (&value->data);
1410 case BHND_NVRAM_VAL_DATA_NONE:
1411 BHND_NV_PANIC("uninitialized value");
1414 BHND_NV_PANIC("unknown storage type: %d", value->data_storage);
1418 * Iterate over all array elements in @p value.
1420 * @param value The value to be iterated
1421 * @param prev A value pointer previously returned by
1422 * bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
1423 * or NULL to begin iteration at the first element.
1424 * @param[in,out] olen If @p prev is non-NULL, @p olen must be a
1425 * pointer to the length previously returned by
1426 * bhnd_nvram_val_next() or bhnd_nvram_val_elem().
1427 * On success, will be set to the next element's
1430 * @retval non-NULL A borrowed reference to the element data.
1431 * @retval NULL If the end of the element array is reached.
1434 bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *olen)
1436 /* Prefer the format implementation */
1437 if (value->fmt->op_next != NULL)
1438 return (value->fmt->op_next(value, prev, olen));
1440 return (bhnd_nvram_val_generic_next(value, prev, olen));
1444 * Return the value's data type.
1446 * @param value The value to be queried.
1449 bhnd_nvram_val_type(bhnd_nvram_val *value)
1451 return (value->data_type);
1455 * Return value's element data type.
1457 * @param value The value to be queried.
1460 bhnd_nvram_val_elem_type(bhnd_nvram_val *value)
1462 return (bhnd_nvram_base_type(value->data_type));
1466 * Return the total number of elements represented by @p value.
1469 bhnd_nvram_val_nelem(bhnd_nvram_val *value)
1472 bhnd_nvram_type type;
1476 /* Prefer format implementation */
1477 if (value->fmt->op_nelem != NULL)
1478 return (value->fmt->op_nelem(value));
1481 * If a custom op_next() is defined, bhnd_nvram_value_nelem() almost
1482 * certainly cannot produce a valid element count; it assumes a standard
1483 * data format that may not apply when custom iteration is required.
1485 * Instead, use bhnd_nvram_val_next() to parse the backing data and
1486 * produce a total count.
1488 if (value->fmt->op_next != NULL) {
1493 while ((next = bhnd_nvram_val_next(value, next, &len)) != NULL)
1499 /* Otherwise, compute the standard element count */
1500 bytes = bhnd_nvram_val_bytes(value, &len, &type);
1501 if ((error = bhnd_nvram_value_nelem(bytes, len, type, &nelem))) {
1502 /* Should always succeed */
1503 BHND_NV_PANIC("error calculating element count for type '%s' "
1504 "with length %zu: %d\n", bhnd_nvram_type_name(type), len,
1512 * Generic implementation of bhnd_nvram_val_op_encode(), compatible with
1513 * all supported NVRAM data types.
1516 bhnd_nvram_val_generic_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
1517 bhnd_nvram_type otype)
1520 bhnd_nvram_type itype;
1523 bhnd_nvram_type otype_base;
1524 size_t limit, nelem, nbytes;
1530 otype_base = bhnd_nvram_base_type(otype);
1531 inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
1534 * Normally, an array type is not universally representable as
1537 * As exceptions, we support conversion directly to/from:
1538 * - CHAR_ARRAY/STRING:
1539 * ->STRING Interpret the character array as a
1540 * non-NUL-terminated string.
1541 * ->CHAR_ARRAY Trim the trailing NUL from the string.
1543 #define BHND_NV_IS_ISO_CONV(_lhs, _rhs) \
1544 ((itype == BHND_NVRAM_TYPE_ ## _lhs && \
1545 otype == BHND_NVRAM_TYPE_ ## _rhs) || \
1546 (itype == BHND_NVRAM_TYPE_ ## _rhs && \
1547 otype == BHND_NVRAM_TYPE_ ## _lhs))
1549 if (BHND_NV_IS_ISO_CONV(CHAR_ARRAY, STRING)) {
1550 return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
1554 #undef BHND_NV_IS_ISO_CONV
1557 * If both input and output are non-array types, try to encode them
1558 * without performing element iteration.
1560 if (!bhnd_nvram_is_array_type(itype) &&
1561 !bhnd_nvram_is_array_type(otype))
1563 return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
1567 /* Determine output byte limit */
1573 /* Iterate over our array elements and encode as the requested
1576 while ((next = bhnd_nvram_val_next(value, next, &next_len))) {
1580 /* If the output type is not an array type, we can only encode
1583 if (nelem > 1 && !bhnd_nvram_is_array_type(otype)) {
1587 /* Determine output offset / limit */
1588 if (nbytes >= limit) {
1592 elem_nbytes = limit - nbytes;
1593 elem_outp = (uint8_t *)outp + nbytes;
1596 /* Attempt encode */
1597 error = bhnd_nvram_val_encode_elem(value, next, next_len,
1598 elem_outp, &elem_nbytes, otype_base);
1600 /* If encoding failed for any reason other than ENOMEM (which
1601 * we'll detect and report below), return immediately */
1602 if (error && error != ENOMEM)
1605 /* Add to total length */
1606 if (SIZE_MAX - nbytes < elem_nbytes)
1607 return (EFTYPE); /* would overflow size_t */
1609 nbytes += elem_nbytes;
1612 /* Provide the actual length */
1615 /* If no output was requested, nothing left to do */
1619 /* Otherwise, report a memory error if the output buffer was too
1628 * Generic implementation of bhnd_nvram_val_op_encode_elem(), compatible with
1629 * all supported NVRAM data types.
1632 bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
1633 size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
1635 bhnd_nvram_type itype;
1637 itype = bhnd_nvram_val_elem_type(value);
1639 case BHND_NVRAM_TYPE_NULL:
1640 return (bhnd_nvram_val_encode_null(inp, ilen, itype, outp, olen,
1643 case BHND_NVRAM_TYPE_DATA:
1644 return (bhnd_nvram_val_encode_data(inp, ilen, itype, outp,
1647 case BHND_NVRAM_TYPE_STRING:
1648 case BHND_NVRAM_TYPE_CHAR:
1649 return (bhnd_nvram_val_encode_string(inp, ilen, itype, outp,
1652 case BHND_NVRAM_TYPE_BOOL:
1653 return (bhnd_nvram_val_encode_bool(inp, ilen, itype, outp, olen,
1656 case BHND_NVRAM_TYPE_UINT8:
1657 case BHND_NVRAM_TYPE_UINT16:
1658 case BHND_NVRAM_TYPE_UINT32:
1659 case BHND_NVRAM_TYPE_UINT64:
1660 case BHND_NVRAM_TYPE_INT8:
1661 case BHND_NVRAM_TYPE_INT16:
1662 case BHND_NVRAM_TYPE_INT32:
1663 case BHND_NVRAM_TYPE_INT64:
1664 return (bhnd_nvram_val_encode_int(inp, ilen, itype, outp, olen,
1667 BHND_NV_PANIC("missing encode_elem() implementation");
1672 * Generic implementation of bhnd_nvram_val_op_next(), compatible with
1673 * all supported NVRAM data types.
1676 bhnd_nvram_val_generic_next(bhnd_nvram_val *value, const void *prev,
1680 bhnd_nvram_type itype;
1683 /* Iterate over the backing representation */
1684 inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
1685 return (bhnd_nvram_value_array_next(inp, ilen, itype, prev, olen));
1689 * Initialize the representation of @p value with @p ptr.
1691 * @param value The value to be initialized.
1692 * @param inp The external representation.
1693 * @param ilen The external representation length, in bytes.
1694 * @param itype The external representation's data type.
1695 * @param flags Value flags.
1697 * @retval 0 success.
1698 * @retval ENOMEM if allocation fails
1699 * @retval EFTYPE if @p itype is not an array type, and @p ilen is not
1700 * equal to the size of a single element of @p itype.
1701 * @retval EFAULT if @p ilen is not correctly aligned for elements of
1705 bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, size_t ilen,
1706 bhnd_nvram_type itype, uint32_t flags)
1711 BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1713 /* Validate alignment */
1714 if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
1717 /* Reference the external data */
1718 if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
1719 (flags & BHND_NVRAM_VAL_STATIC_DATA))
1721 if (flags & BHND_NVRAM_VAL_STATIC_DATA)
1722 value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
1724 value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
1726 value->data.ptr = inp;
1727 value->data_type = itype;
1728 value->data_len = ilen;
1732 /* Fetch reference to (or allocate) an appropriately sized buffer */
1733 bytes = bhnd_nvram_val_alloc_bytes(value, ilen, itype, flags);
1738 memcpy(bytes, inp, ilen);
1744 * Initialize the internal inline representation of @p value with a copy of
1745 * the data referenced by @p inp of @p itype.
1747 * If @p inp is NULL, @p itype and @p ilen will be validated, but no data will
1750 * @param value The value to be initialized.
1751 * @param inp The input data to be copied, or NULL to verify
1752 * that data of @p ilen and @p itype can be represented
1754 * @param ilen The size of the external buffer to be allocated.
1755 * @param itype The type of the external buffer to be allocated.
1758 * @retval ENOMEM if @p ilen is too large to be represented inline.
1759 * @retval EFAULT if @p ilen is not correctly aligned for elements of
1763 bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen,
1764 bhnd_nvram_type itype)
1766 BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1768 #define NV_STORE_INIT_INLINE() do { \
1769 value->data_len = ilen; \
1770 value->data_type = itype; \
1773 #define NV_STORE_INLINE(_type, _dest) do { \
1774 if (ilen != sizeof(_type)) \
1777 if (inp != NULL) { \
1778 value->data._dest[0] = *(const _type *)inp; \
1779 NV_STORE_INIT_INLINE(); \
1783 #define NV_COPY_ARRRAY_INLINE(_type, _dest) do { \
1784 if (ilen % sizeof(_type) != 0) \
1787 if (ilen > nitems(value->data. _dest)) \
1793 memcpy(&value->data._dest, inp, ilen); \
1794 if (inp != NULL) { \
1795 memcpy(&value->data._dest, inp, ilen); \
1796 NV_STORE_INIT_INLINE(); \
1800 /* Attempt to copy to inline storage */
1802 case BHND_NVRAM_TYPE_NULL:
1806 /* Nothing to copy */
1807 NV_STORE_INIT_INLINE();
1810 case BHND_NVRAM_TYPE_CHAR:
1811 NV_STORE_INLINE(uint8_t, ch);
1814 case BHND_NVRAM_TYPE_BOOL:
1815 NV_STORE_INLINE(bhnd_nvram_bool_t, b);
1818 case BHND_NVRAM_TYPE_UINT8:
1819 case BHND_NVRAM_TYPE_INT8:
1820 NV_STORE_INLINE(uint8_t, u8);
1823 case BHND_NVRAM_TYPE_UINT16:
1824 case BHND_NVRAM_TYPE_INT16:
1825 NV_STORE_INLINE(uint16_t, u16);
1828 case BHND_NVRAM_TYPE_UINT32:
1829 case BHND_NVRAM_TYPE_INT32:
1830 NV_STORE_INLINE(uint32_t, u32);
1833 case BHND_NVRAM_TYPE_UINT64:
1834 case BHND_NVRAM_TYPE_INT64:
1835 NV_STORE_INLINE(uint32_t, u32);
1838 case BHND_NVRAM_TYPE_CHAR_ARRAY:
1839 NV_COPY_ARRRAY_INLINE(uint8_t, ch);
1842 case BHND_NVRAM_TYPE_DATA:
1843 case BHND_NVRAM_TYPE_UINT8_ARRAY:
1844 case BHND_NVRAM_TYPE_INT8_ARRAY:
1845 NV_COPY_ARRRAY_INLINE(uint8_t, u8);
1848 case BHND_NVRAM_TYPE_UINT16_ARRAY:
1849 case BHND_NVRAM_TYPE_INT16_ARRAY:
1850 NV_COPY_ARRRAY_INLINE(uint16_t, u16);
1853 case BHND_NVRAM_TYPE_UINT32_ARRAY:
1854 case BHND_NVRAM_TYPE_INT32_ARRAY:
1855 NV_COPY_ARRRAY_INLINE(uint32_t, u32);
1858 case BHND_NVRAM_TYPE_UINT64_ARRAY:
1859 case BHND_NVRAM_TYPE_INT64_ARRAY:
1860 NV_COPY_ARRRAY_INLINE(uint64_t, u64);
1863 case BHND_NVRAM_TYPE_BOOL_ARRAY:
1864 NV_COPY_ARRRAY_INLINE(bhnd_nvram_bool_t, b);
1867 case BHND_NVRAM_TYPE_STRING:
1868 case BHND_NVRAM_TYPE_STRING_ARRAY:
1869 if (ilen > sizeof(value->data.ch))
1873 memcpy(&value->data.ch, inp, ilen);
1874 NV_STORE_INIT_INLINE();
1880 #undef NV_STORE_INIT_INLINE
1881 #undef NV_STORE_INLINE
1882 #undef NV_COPY_ARRRAY_INLINE
1884 BHND_NV_PANIC("unknown data type %d", itype);
1888 * Initialize the internal representation of @p value with a buffer allocation
1889 * of @p len and @p itype, returning a pointer to the allocated buffer.
1891 * If a buffer of @p len and @p itype can be represented inline, no
1892 * external buffer will be allocated, and instead a pointer to the inline
1893 * data representation will be returned.
1895 * @param value The value to be initialized.
1896 * @param ilen The size of the external buffer to be allocated.
1897 * @param itype The type of the external buffer to be allocated.
1898 * @param flags Value flags.
1900 * @retval non-null The newly allocated buffer.
1901 * @retval NULL If allocation failed.
1902 * @retval NULL If @p value is an externally allocated instance.
1905 bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
1906 bhnd_nvram_type itype, uint32_t flags)
1910 BHND_NVRAM_VAL_ASSERT_EMPTY(value);
1912 /* Can we use inline storage? */
1913 if (bhnd_nvram_val_set_inline(value, NULL, ilen, itype) == 0) {
1914 BHND_NV_ASSERT(sizeof(value->data) >= ilen,
1915 ("ilen exceeds inline storage"));
1917 value->data_type = itype;
1918 value->data_len = ilen;
1919 value->data_storage = BHND_NVRAM_VAL_DATA_INLINE;
1920 return (&value->data);
1923 /* Is allocation permitted? */
1924 if (!(flags & BHND_NVRAM_VAL_DYNAMIC))
1927 /* Allocate external storage */
1928 if ((ptr = bhnd_nv_malloc(ilen)) == NULL)
1931 value->data.ptr = ptr;
1932 value->data_len = ilen;
1933 value->data_type = itype;
1934 value->data_storage = BHND_NVRAM_VAL_DATA_EXT_ALLOC;