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