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