freebsd-dev/sys/dev/bhnd/nvram/bhnd_nvram_value.c

1312 lines
35 KiB
C
Raw Normal View History

bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
/*-
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/sbuf.h>
#ifdef _KERNEL
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <machine/_inttypes.h>
#else /* !_KERNEL */
#include <inttypes.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#endif /* _KERNEL */
#include "bhnd_nvram_private.h"
#include "bhnd_nvram_valuevar.h"
static void *bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
bhnd_nvram_type itype, uint32_t flags);
static int bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp,
size_t ilen, bhnd_nvram_type itype, uint32_t flags);
static int bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
const void *inp, size_t ilen, bhnd_nvram_type itype);
#define BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage) \
(bhnd_nvram_val) { \
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
.refs = 1, \
.val_storage = _storage, \
.fmt = _fmt, \
.data_storage = BHND_NVRAM_VAL_DATA_NONE, \
};
/** Assert that @p value's backing representation state has initialized
* as empty. */
#define BHND_NVRAM_VAL_ASSERT_EMPTY(_value) \
BHND_NV_ASSERT( \
value->data_storage == BHND_NVRAM_VAL_DATA_NONE && \
value->data_len == 0 && \
value->data.ptr == NULL, \
("previously initialized value"))
/* Common initialization support for bhnd_nvram_val_init() and
* bhnd_nvram_val_new() */
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)
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
{
void *outp;
bhnd_nvram_type otype;
size_t olen;
int error;
/* Determine expected data type, and allow the format to delegate to
* a new format instance */
if (fmt != NULL && fmt->op_filter != NULL) {
const bhnd_nvram_val_fmt *nfmt = fmt;
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
/* Use the filter function to determine whether direct
* initialization from is itype permitted */
error = fmt->op_filter(&nfmt, inp, ilen, itype);
if (error)
return (error);
/* Retry initialization with new format? */
if (nfmt != fmt) {
return (bhnd_nvram_val_init_common(value, val_storage,
nfmt, inp, ilen, itype, flags));
}
/* Value can be initialized with provided input type */
otype = itype;
} else if (fmt != NULL) {
/* Value must be initialized with the format's native
* type */
otype = fmt->native_type;
} else {
/* No format specified; we can initialize directly from the
* input data, and we'll handle all format operations
* internally. */
otype = itype;
}
/* Initialize value instance */
*value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
/* If input data already in native format, init directly. */
if (otype == itype) {
error = bhnd_nvram_val_set(value, inp, ilen, itype, flags);
if (error)
return (error);
return (0);
}
/* Determine size when encoded in native format */
error = bhnd_nvram_value_coerce(inp, ilen, itype, NULL, &olen, otype);
if (error)
return (error);
/* Fetch reference to (or allocate) an appropriately sized buffer */
outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
if (outp == NULL)
return (ENOMEM);
/* Perform encode */
error = bhnd_nvram_value_coerce(inp, ilen, itype, outp, &olen, otype);
if (error)
return (error);
return (0);
}
/**
* Initialize an externally allocated instance of @p value with @p fmt from the
* given @p inp buffer of @p itype and @p ilen.
*
* On success, the caller owns a reference to @p value, and is responsible for
* freeing any resources allocated for @p value via bhnd_nvram_val_release().
*
* @param value The externally allocated value instance to be
* initialized.
* @param fmt The value's format, or NULL to use the default format
* for @p itype.
* @param inp Input buffer.
* @param ilen Input buffer length.
* @param itype Input buffer type.
* @param flags Value flags (see BHND_NVRAM_VAL_*).
*
* @retval 0 success
* @retval ENOMEM If allocation fails.
* @retval EFTYPE If @p fmt initialization from @p itype is unsupported.
* @retval EFAULT if @p ilen is not correctly aligned for elements of
* @p itype.
* @retval ERANGE If value coercion would overflow (or underflow) the
* @p fmt representation.
*/
int
bhnd_nvram_val_init(bhnd_nvram_val *value, const bhnd_nvram_val_fmt *fmt,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
{
int error;
error = bhnd_nvram_val_init_common(value, BHND_NVRAM_VAL_STORAGE_AUTO,
fmt, inp, ilen, itype, flags);
if (error)
bhnd_nvram_val_release(value);
return (error);
}
/**
* Allocate a value instance with @p fmt, and attempt to initialize its internal
* representation from the given @p inp buffer of @p itype and @p ilen.
*
* On success, the caller owns a reference to @p value, and is responsible for
* freeing any resources allocated for @p value via bhnd_nvram_val_release().
*
* @param[out] value On success, the allocated value instance.
* @param fmt The value's format, or NULL to use the default format
* for @p itype.
* @param inp Input buffer.
* @param ilen Input buffer length.
* @param itype Input buffer type.
* @param flags Value flags (see BHND_NVRAM_VAL_*).
*
* @retval 0 success
* @retval ENOMEM If allocation fails.
* @retval EFTYPE If @p fmt initialization from @p itype is unsupported.
* @retval EFAULT if @p ilen is not correctly aligned for elements of
* @p itype.
* @retval ERANGE If value coercion would overflow (or underflow) the
* @p fmt representation.
*/
int
bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
{
int error;
/* Allocate new instance */
if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
return (ENOMEM);
/* Perform common initialization. */
error = bhnd_nvram_val_init_common(*value,
BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, inp, ilen, itype, flags);
if (error) {
/* Will also free() the value allocation */
bhnd_nvram_val_release(*value);
}
return (error);
}
/**
* Copy or retain a reference to @p value.
*
* On success, the caller is responsible for freeing the result via
* bhnd_nvram_val_release().
*
* @param value The value to be copied (or retained).
*
* @retval bhnd_nvram_val if @p value was successfully copied or retained.
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
* @retval NULL if allocation failed.
*/
bhnd_nvram_val *
bhnd_nvram_val_copy(bhnd_nvram_val *value)
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
{
bhnd_nvram_val *result;
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
const void *bytes;
bhnd_nvram_type type;
size_t len;
uint32_t flags;
int error;
/* If dynamically allocated, simply bump the reference count */
if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC) {
refcount_acquire(&value->refs);
return (value);
}
/* Otherwise, we need to perform an actual copy */
BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
"active refcount (%u)", value->refs));
/* Compute the new value's flags based on the source value */
switch (value->data_storage) {
case BHND_NVRAM_VAL_DATA_NONE:
case BHND_NVRAM_VAL_DATA_INLINE:
case BHND_NVRAM_VAL_DATA_EXT_WEAK:
case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
/* Copy the source data and permit additional allocation if the
* value cannot be represented inline */
flags = BHND_NVRAM_VAL_COPY_DATA|BHND_NVRAM_VAL_DYNAMIC;
break;
case BHND_NVRAM_VAL_DATA_EXT_STATIC:
flags = BHND_NVRAM_VAL_STATIC_DATA;
break;
default:
BHND_NV_PANIC("invalid storage type: %d", value->data_storage);
}
/* Allocate new value copy */
bytes = bhnd_nvram_val_bytes(value, &len, &type);
error = bhnd_nvram_val_new(&result, value->fmt, bytes, len, type,
flags);
if (error) {
BHND_NV_LOG("copy failed: %d", error);
return (NULL);
}
return (result);
}
/**
* Release a reference to @p value.
*
* If this is the last reference, all associated resources will be freed.
*
* @param value The value to be released.
*/
void
bhnd_nvram_val_release(bhnd_nvram_val *value)
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
{
BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
/* Drop reference */
if (!refcount_release(&value->refs))
return;
/* Free allocated external representation data */
if (value->data_storage == BHND_NVRAM_VAL_DATA_EXT_ALLOC)
bhnd_nv_free(__DECONST(void *, value->data.ptr));
/* Free instance if dynamically allocated */
if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
bhnd_nv_free(value);
}
/**
* Standard string/char array/char encoding implementation.
*
* Input type must be one of:
* - BHND_NVRAM_TYPE_STRING
* - BHND_NVRAM_TYPE_CHAR
* - BHND_NVRAM_TYPE_CHAR_ARRAY
*/
static int
bhnd_nvram_val_encode_string(void *outp, size_t *olen, bhnd_nvram_type otype,
const void *inp, size_t ilen, bhnd_nvram_type itype)
{
const char *cstr;
bhnd_nvram_type otype_base;
size_t cstr_size, cstr_len;
size_t limit, nbytes;
BHND_NV_ASSERT(
itype == BHND_NVRAM_TYPE_STRING ||
itype == BHND_NVRAM_TYPE_CHAR ||
itype == BHND_NVRAM_TYPE_CHAR_ARRAY,
("unsupported type: %d", itype));
cstr = inp;
cstr_size = ilen;
nbytes = 0;
otype_base = bhnd_nvram_base_type(otype);
/* Determine output byte limit */
if (outp != NULL)
limit = *olen;
else
limit = 0;
/* Determine string length, minus trailing NUL (if any) */
cstr_len = strnlen(cstr, cstr_size);
/* Parse the field data */
switch (otype) {
case BHND_NVRAM_TYPE_CHAR:
case BHND_NVRAM_TYPE_CHAR_ARRAY:
/* String must contain exactly 1 non-terminating-NUL character
* to be represented as a single char */
if (!bhnd_nvram_is_array_type(otype)) {
if (cstr_len != 1)
return (EFTYPE);
}
/* Copy out the characters directly (excluding trailing NUL) */
for (size_t i = 0; i < cstr_len; i++) {
if (limit > nbytes)
*((uint8_t *)outp + nbytes) = cstr[i];
nbytes++;
}
/* Provide required length */
*olen = nbytes;
if (limit < *olen && outp != NULL)
return (ENOMEM);
return (0);
case BHND_NVRAM_TYPE_UINT8:
case BHND_NVRAM_TYPE_UINT8_ARRAY:
case BHND_NVRAM_TYPE_UINT16:
case BHND_NVRAM_TYPE_UINT16_ARRAY:
case BHND_NVRAM_TYPE_UINT32:
case BHND_NVRAM_TYPE_UINT32_ARRAY:
case BHND_NVRAM_TYPE_UINT64:
case BHND_NVRAM_TYPE_UINT64_ARRAY:
case BHND_NVRAM_TYPE_INT8:
case BHND_NVRAM_TYPE_INT8_ARRAY:
case BHND_NVRAM_TYPE_INT16:
case BHND_NVRAM_TYPE_INT16_ARRAY:
case BHND_NVRAM_TYPE_INT32:
case BHND_NVRAM_TYPE_INT32_ARRAY:
case BHND_NVRAM_TYPE_INT64:
case BHND_NVRAM_TYPE_INT64_ARRAY: {
const char *p;
size_t plen, parsed_len;
int error;
/* Trim leading/trailing whitespace */
p = cstr;
plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
/* Try to parse the integer value */
error = bhnd_nvram_parse_int(p, plen, 0, &parsed_len, outp,
olen, otype_base);
if (error) {
BHND_NV_DEBUG("error parsing '%.*s' as integer: %d\n",
BHND_NV_PRINT_WIDTH(plen), p, error);
return (error);
}
/* Do additional bytes remain unparsed? */
if (plen != parsed_len) {
BHND_NV_DEBUG("error parsing '%.*s' as a single "
"integer value; trailing garbage '%.*s'\n",
BHND_NV_PRINT_WIDTH(plen), p,
BHND_NV_PRINT_WIDTH(plen-parsed_len), p+parsed_len);
return (EFTYPE);
}
return (0);
}
case BHND_NVRAM_TYPE_STRING:
case BHND_NVRAM_TYPE_STRING_ARRAY:
/* Copy out the string representation as-is */
*olen = cstr_size;
/* Need additional space for trailing NUL? */
if (cstr_len == cstr_size)
(*olen)++;
/* Skip output? */
if (outp == NULL)
return (0);
/* Verify required length */
if (limit < *olen)
return (ENOMEM);
/* Copy and NUL terminate */
strncpy(outp, cstr, cstr_len);
*((char *)outp + cstr_len) = '\0';
return (0);
}
BHND_NV_PANIC("unknown type %s", bhnd_nvram_type_name(otype));
}
/**
* Standard integer encoding implementation.
*/
static int
bhnd_nvram_val_encode_int(void *outp, size_t *olen, bhnd_nvram_type otype,
const void *inp, size_t ilen, bhnd_nvram_type itype)
{
bhnd_nvram_type otype_base;
size_t limit, nbytes;
bool itype_signed, otype_signed, otype_int;
union {
uint64_t u64;
int64_t i64;
} intv;
BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("non-integer type"));
/* Determine output byte limit */
if (outp != NULL)
limit = *olen;
else
limit = 0;
/* Fetch output type info */
otype_base = bhnd_nvram_base_type(otype);
otype_int = bhnd_nvram_is_int_type(otype);
otype_signed = bhnd_nvram_is_signed_type(otype_base);
/*
* Promote integer value to a common 64-bit representation.
*/
switch (itype) {
case BHND_NVRAM_TYPE_UINT8:
if (ilen != sizeof(uint8_t))
return (EFAULT);
itype_signed = false;
intv.u64 = *(const uint8_t *)inp;
break;
case BHND_NVRAM_TYPE_UINT16:
if (ilen != sizeof(uint16_t))
return (EFAULT);
itype_signed = false;
intv.u64 = *(const uint16_t *)inp;
break;
case BHND_NVRAM_TYPE_UINT32:
if (ilen != sizeof(uint32_t))
return (EFAULT);
itype_signed = false;
intv.u64 = *(const uint32_t *)inp;
break;
case BHND_NVRAM_TYPE_UINT64:
if (ilen != sizeof(uint64_t))
return (EFAULT);
itype_signed = false;
intv.u64 = *(const uint64_t *)inp;
break;
case BHND_NVRAM_TYPE_INT8:
if (ilen != sizeof(int8_t))
return (EFAULT);
itype_signed = true;
intv.i64 = *(const int8_t *)inp;
break;
case BHND_NVRAM_TYPE_INT16:
if (ilen != sizeof(int16_t))
return (EFAULT);
itype_signed = true;
intv.i64 = *(const int16_t *)inp;
break;
case BHND_NVRAM_TYPE_INT32:
if (ilen != sizeof(int32_t))
return (EFAULT);
itype_signed = true;
intv.i64 = *(const int32_t *)inp;
break;
case BHND_NVRAM_TYPE_INT64:
if (ilen != sizeof(int32_t))
return (EFAULT);
itype_signed = true;
intv.i64 = *(const int32_t *)inp;
break;
default:
BHND_NV_PANIC("invalid type %d\n", itype);
}
/* Perform signed/unsigned conversion */
if (itype_signed && otype_int && !otype_signed) {
if (intv.i64 < 0) {
/* Can't represent negative value */
BHND_NV_LOG("cannot represent %" PRId64 " as %s\n",
intv.i64, bhnd_nvram_type_name(otype));
return (ERANGE);
}
/* Convert to unsigned representation */
intv.u64 = intv.i64;
} else if (!itype_signed && otype_int && otype_signed) {
/* Handle unsigned -> signed coercions */
if (intv.u64 > INT64_MAX) {
/* Can't represent positive value */
BHND_NV_LOG("cannot represent %" PRIu64 " as %s\n",
intv.u64, bhnd_nvram_type_name(otype));
return (ERANGE);
}
/* Convert to signed representation */
intv.i64 = intv.u64;
}
/* Write output */
switch (otype) {
case BHND_NVRAM_TYPE_CHAR:
case BHND_NVRAM_TYPE_CHAR_ARRAY:
case BHND_NVRAM_TYPE_UINT8:
case BHND_NVRAM_TYPE_UINT8_ARRAY:
if (intv.u64 > UINT8_MAX)
return (ERANGE);
nbytes = sizeof(uint8_t);
if (limit >= nbytes)
*((uint8_t *)outp) = (uint8_t)intv.u64;
break;
case BHND_NVRAM_TYPE_UINT16:
case BHND_NVRAM_TYPE_UINT16_ARRAY:
if (intv.u64 > UINT16_MAX)
return (ERANGE);
nbytes = sizeof(uint16_t);
if (limit >= nbytes)
*((uint16_t *)outp) = (uint16_t)intv.u64;
break;
case BHND_NVRAM_TYPE_UINT32:
case BHND_NVRAM_TYPE_UINT32_ARRAY:
if (intv.u64 > UINT32_MAX)
return (ERANGE);
nbytes = sizeof(uint32_t);
if (limit >= nbytes)
*((uint32_t *)outp) = (uint32_t)intv.u64;
break;
case BHND_NVRAM_TYPE_UINT64:
case BHND_NVRAM_TYPE_UINT64_ARRAY:
nbytes = sizeof(uint64_t);
if (limit >= nbytes)
*((uint64_t *)outp) = intv.u64;
break;
case BHND_NVRAM_TYPE_INT8:
case BHND_NVRAM_TYPE_INT8_ARRAY:
if (intv.i64 < INT8_MIN || intv.i64 > INT8_MAX)
return (ERANGE);
nbytes = sizeof(int8_t);
if (limit >= nbytes)
*((int8_t *)outp) = (int8_t)intv.i64;
break;
case BHND_NVRAM_TYPE_INT16:
case BHND_NVRAM_TYPE_INT16_ARRAY:
if (intv.i64 < INT16_MIN || intv.i64 > INT16_MAX)
return (ERANGE);
nbytes = sizeof(int16_t);
if (limit >= nbytes)
*((int16_t *)outp) = (int16_t)intv.i64;
break;
case BHND_NVRAM_TYPE_INT32:
case BHND_NVRAM_TYPE_INT32_ARRAY:
if (intv.i64 < INT32_MIN || intv.i64 > INT32_MAX)
return (ERANGE);
nbytes = sizeof(int32_t);
if (limit >= nbytes)
*((int32_t *)outp) = (int32_t)intv.i64;
break;
case BHND_NVRAM_TYPE_INT64:
case BHND_NVRAM_TYPE_INT64_ARRAY:
nbytes = sizeof(int64_t);
if (limit >= nbytes)
*((int64_t *)outp) = intv.i64;
break;
case BHND_NVRAM_TYPE_STRING:
case BHND_NVRAM_TYPE_STRING_ARRAY: {
ssize_t len;
/* Attempt to write the entry + NUL */
if (otype_signed) {
len = snprintf(outp, limit, "%" PRId64, intv.i64);
} else {
len = snprintf(outp, limit, "%" PRIu64, intv.u64);
}
if (len < 0) {
BHND_NV_LOG("snprintf() failed: %zd\n", len);
return (EFTYPE);
}
/* Set total length to the formatted string length, plus
* trailing NUL */
nbytes = len + 1;
break;
}
default:
BHND_NV_LOG("unknown type %s\n", bhnd_nvram_type_name(otype));
return (EFTYPE);
}
/* Provide required length */
*olen = nbytes;
if (limit < *olen) {
if (outp == NULL)
return (0);
return (ENOMEM);
}
return (0);
}
/**
* Encode the given @p value as @p otype, writing the result to @p outp.
*
* @param value The value to be encoded.
* @param[out] outp On success, the value will be written to this
* buffer. This argment may be NULL if the value is
* not desired.
* @param[in,out] olen The capacity of @p outp. On success, will be set
* to the actual size of the requested value.
* @param otype The data type to be written to @p outp.
*
* @retval 0 success
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
* is too small to hold the encoded value.
* @retval EFTYPE If value coercion from @p value to @p otype is
* impossible.
* @retval ERANGE If value coercion would overflow (or underflow) the
* a @p otype representation.
*/
int
bhnd_nvram_val_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
bhnd_nvram_type otype)
{
/* Prefer format implementation */
if (value->fmt != NULL && value->fmt->op_encode != NULL)
return (value->fmt->op_encode(value, outp, olen, otype));
return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
}
/**
* Encode the given @p value's element as @p otype, writing the result to
* @p outp.
*
* @param inp The element to be be encoded. Must be a value
* previously returned by bhnd_nvram_val_next()
* or bhnd_nvram_val_elem().
* @param ilen The size of @p inp, as returned by
* bhnd_nvram_val_next() or bhnd_nvram_val_elem().
* @param[out] outp On success, the value will be written to this
* buffer. This argment may be NULL if the value is
* not desired.
* @param[in,out] olen The capacity of @p outp. On success, will be set
* to the actual size of the requested value.
* @param otype The data type to be written to @p outp.
*
* @retval 0 success
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
* is too small to hold the encoded value.
* @retval EFTYPE If value coercion from @p value to @p otype is
* impossible.
* @retval ERANGE If value coercion would overflow (or underflow) the
* a @p otype representation.
*/
int
bhnd_nvram_val_encode_elem(bhnd_nvram_val *value, const void *inp,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
{
/* Prefer format implementation */
if (value->fmt != NULL && value->fmt->op_encode_elem != NULL) {
return (value->fmt->op_encode_elem(value, inp, ilen, outp,
olen, otype));
}
return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen, outp,
olen, otype));
}
/**
* Return the type, size, and a pointer to the internal representation
* of @p value.
*
* @param value The value to be queried.
* @param[out] olen Size of the returned data, in bytes.
* @param[out] otype Data type.
*/
const void *
bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
bhnd_nvram_type *otype)
{
/* Provide type and length */
*otype = value->data_type;
*olen = value->data_len;
switch (value->data_storage) {
case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
case BHND_NVRAM_VAL_DATA_EXT_STATIC:
case BHND_NVRAM_VAL_DATA_EXT_WEAK:
/* Return a pointer to external storage */
return (value->data.ptr);
case BHND_NVRAM_VAL_DATA_INLINE:
/* Return a pointer to inline storage */
return (&value->data);
case BHND_NVRAM_VAL_DATA_NONE:
BHND_NV_PANIC("uninitialized value");
}
BHND_NV_PANIC("unknown storage type: %d", value->data_storage);
}
/**
* Iterate over all array elements in @p value.
*
* @param value The value to be iterated
* @param prev A value pointer previously returned by
* bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
* or NULL to begin iteration at the first element.
* @param[in,out] len If prev is non-NULL, len must be a pointer
* to the length previously returned by
* bhnd_nvram_val_next() or bhnd_nvram_val_elem().
* On success, will be set to the next element's
* length, in bytes.
*
* @retval non-NULL A borrowed reference to the element data.
* @retval NULL If the end of the element array is reached.
*/
const void *
bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *len)
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
{
/* Prefer the format implementation */
if (value->fmt != NULL && value->fmt->op_next != NULL)
return (value->fmt->op_next(value, prev, len));
return (bhnd_nvram_val_generic_next(value, prev, len));
}
/**
* Return value's element data type.
*
* @param value The value to be queried.
*/
bhnd_nvram_type
bhnd_nvram_val_elem_type(bhnd_nvram_val *value)
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
{
return (bhnd_nvram_base_type(value->data_type));
}
/**
* Return the total number of elements represented by @p value.
*/
size_t
bhnd_nvram_val_nelem(bhnd_nvram_val *value)
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
{
const void *bytes;
bhnd_nvram_type type;
size_t nelem, len;
int error;
/* Prefer format implementation */
if (value->fmt != NULL && value->fmt->op_nelem != NULL)
return (value->fmt->op_nelem(value));
/*
* If a custom op_next() is defined, bhnd_nvram_value_nelem() almost
* certainly cannot produce a valid element count; it assumes a standard
* data format that may not apply when custom iteration is required.
*
* Instead, use bhnd_nvram_val_next() to parse the backing data and
* produce a total count.
*/
if (value->fmt != NULL && value->fmt->op_next != NULL) {
const void *next;
next = NULL;
nelem = 0;
while ((next = bhnd_nvram_val_next(value, next, &len)) != NULL)
nelem++;
return (nelem);
}
/* Otherwise, compute the standard element count */
bytes = bhnd_nvram_val_bytes(value, &len, &type);
if ((error = bhnd_nvram_value_nelem(type, bytes, len, &nelem))) {
/* Should always succeed */
BHND_NV_PANIC("error calculating element count for type '%s' "
"with length %zu: %d\n", bhnd_nvram_type_name(type), len,
error);
}
return (nelem);
}
/**
* Generic implementation of bhnd_nvram_val_op_encode(), compatible with
* all supported NVRAM data types.
*/
int
bhnd_nvram_val_generic_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
bhnd_nvram_type otype)
{
const void *inp;
bhnd_nvram_type itype;
size_t ilen;
const void *next;
bhnd_nvram_type otype_base;
size_t limit, nelem, nbytes;
size_t next_len;
int error;
nbytes = 0;
nelem = 0;
otype_base = bhnd_nvram_base_type(otype);
/*
* Normally, a rank polymorphic type like a character array would not
* be representable as a rank 1 type.
*
* As a special-cased exception, we can support conversion directly
* from CHAR_ARRAY to STRING by treating the character array as a
* non-NUL-terminated string.
*
* This conversion is isomorphic; we also support conversion directly
* from a STRING to a CHAR_ARRAY by the same mechanism.
*/
inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
if ((itype == BHND_NVRAM_TYPE_CHAR_ARRAY &&
otype == BHND_NVRAM_TYPE_STRING) ||
(itype == BHND_NVRAM_TYPE_STRING &&
otype == BHND_NVRAM_TYPE_CHAR_ARRAY))
{
return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
otype));
}
/*
* If both input and output are non-array types, try to encode them
* without performing element iteration.
*/
if (!bhnd_nvram_is_array_type(itype) &&
!bhnd_nvram_is_array_type(otype))
{
return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
otype));
}
/* Determine output byte limit */
if (outp != NULL)
limit = *olen;
else
limit = 0;
/* Iterate over our array elements and encode as the requested
* type */
next = NULL;
while ((next = bhnd_nvram_val_next(value, next, &next_len))) {
void *elem_outp;
size_t elem_nbytes;
/* If the output type is not an array type, we can only encode
* one element */
nelem++;
if (nelem > 1 && !bhnd_nvram_is_array_type(otype)) {
return (EFTYPE);
}
/* Determine output offset / limit */
if (nbytes >= limit) {
elem_nbytes = 0;
elem_outp = NULL;
} else {
elem_nbytes = limit - nbytes;
elem_outp = (uint8_t *)outp + nbytes;
}
/* Attempt encode */
error = bhnd_nvram_val_encode_elem(value, next, next_len,
elem_outp, &elem_nbytes, otype_base);
/* If encoding failed for any reason other than ENOMEM (which
* we'll detect and report below), return immediately */
if (error && error != ENOMEM)
return (error);
/* Add to total length */
if (SIZE_MAX - nbytes < elem_nbytes)
return (EFTYPE); /* would overflow size_t */
nbytes += elem_nbytes;
}
/* Provide the actual length */
*olen = nbytes;
/* If no output was requested, nothing left to do */
if (outp == NULL)
return (0);
/* Otherwise, report a memory error if the output buffer was too
* small */
if (limit < nbytes)
return (ENOMEM);
return (0);
}
/**
* Generic implementation of bhnd_nvram_val_op_encode_elem(), compatible with
* all supported NVRAM data types.
*/
int
bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
{
bhnd_nvram_type itype;
itype = bhnd_nvram_val_elem_type(value);
switch (itype) {
case BHND_NVRAM_TYPE_STRING:
case BHND_NVRAM_TYPE_CHAR:
case BHND_NVRAM_TYPE_CHAR_ARRAY:
return (bhnd_nvram_val_encode_string(outp, olen, otype, inp,
ilen, itype));
case BHND_NVRAM_TYPE_UINT8:
case BHND_NVRAM_TYPE_UINT16:
case BHND_NVRAM_TYPE_UINT32:
case BHND_NVRAM_TYPE_UINT64:
case BHND_NVRAM_TYPE_INT8:
case BHND_NVRAM_TYPE_INT16:
case BHND_NVRAM_TYPE_INT32:
case BHND_NVRAM_TYPE_INT64:
return (bhnd_nvram_val_encode_int(outp, olen, otype, inp, ilen,
itype));
default:
BHND_NV_PANIC("missing encode_elem() implementation");
}
}
/**
* Generic implementation of bhnd_nvram_val_op_next(), compatible with
* all supported NVRAM data types.
*/
const void *
bhnd_nvram_val_generic_next(bhnd_nvram_val *value, const void *prev,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
size_t *len)
{
const uint8_t *inp;
const uint8_t *next;
bhnd_nvram_type itype;
size_t ilen;
size_t offset;
/* Otherwise, default to iterating over the backing representation
* according to its native representation */
inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
/* First element */
if (prev == NULL) {
/* Zero-length array? */
if (ilen == 0)
return (NULL);
*len = bhnd_nvram_value_size(itype, inp, ilen, 1);
return (inp);
}
/* Advance to next element */
BHND_NV_ASSERT(prev >= (const void *)inp, ("invalid cookiep"));
next = (const uint8_t *)prev + *len;
offset = (size_t)(next - inp);
if (offset >= ilen) {
/* Hit end of the array */
return (NULL);
}
/* Determine element size */
*len = bhnd_nvram_value_size(itype, next, ilen - offset, 1);
if (ilen - offset < *len)
BHND_NV_PANIC("short element -- misaligned representation");
return (next);
}
/**
* Initialize the representation of @p value with @p ptr.
*
* If @p value is an externally allocated instance and the representation
* cannot be represented inline, the given data will not be copied, and @p ptr
* must remain valid for the lifetime of @p value.
*
* Otherwise, @p value will be initialized with a copy of the @p ptr.
*
* @param value The value to be initialized.
* @param inp The external representation.
* @param ilen The external representation length, in bytes.
* @param itype The external representation's data type.
* @param flags Value flags.
*
* @retval 0 success.
* @retval ENOMEM if allocation fails
* @retval EFTYPE if @p itype is not an array type, and @p ilen is not
* equal to the size of a single element of @p itype.
* @retval EFAULT if @p ilen is not correctly aligned for elements of
* @p itype.
*/
static int
bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, size_t ilen,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
bhnd_nvram_type itype, uint32_t flags)
{
void *bytes;
BHND_NVRAM_VAL_ASSERT_EMPTY(value);
/* Reference the external data */
if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
(flags & BHND_NVRAM_VAL_STATIC_DATA))
{
if (flags & BHND_NVRAM_VAL_BORROW_DATA)
value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
else
value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
value->data.ptr = inp;
value->data_type = itype;
value->data_len = ilen;
return (0);
}
/* Fetch reference to (or allocate) an appropriately sized buffer */
bytes = bhnd_nvram_val_alloc_bytes(value, ilen, itype, flags);
if (bytes == NULL)
return (ENOMEM);
/* Copy data */
memcpy(bytes, inp, ilen);
return (0);
}
/**
* Initialize the internal inline representation of @p value with a copy of
* the data referenced by @p inp of @p itype.
*
* If @p inp is NULL, @p itype and @p ilen will be validated, but no data will
* be copied.
*
* @param value The value to be initialized.
* @param inp The input data to be copied, or NULL to verify
* that data of @p ilen and @p itype can be represented
* inline.
* @param ilen The size of the external buffer to be allocated.
* @param itype The type of the external buffer to be allocated.
*
* @retval 0 success
* @retval ENOMEM if @p ilen is too large to be represented inline.
* @retval EFAULT if @p ilen is not correctly aligned for elements of
* @p itype.
*/
static int
bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
bhnd_nvram_type itype)
{
BHND_NVRAM_VAL_ASSERT_EMPTY(value);
#define NV_STORE_INIT_INLINE() do { \
value->data_len = ilen; \
} while(0)
#define NV_STORE_INLINE(_type, _dest) do { \
if (ilen != sizeof(_type)) \
return (EFAULT); \
\
if (inp != NULL) { \
value->data._dest[0] = *(const _type *)inp; \
NV_STORE_INIT_INLINE(); \
} \
} while (0)
#define NV_COPY_ARRRAY_INLINE(_type, _dest) do { \
if (ilen % sizeof(_type) != 0) \
return (EFAULT); \
\
if (ilen > nitems(value->data. _dest)) \
return (ENOMEM); \
\
if (inp == NULL) \
return (0); \
\
memcpy(&value->data._dest, inp, ilen); \
if (inp != NULL) { \
memcpy(&value->data._dest, inp, ilen); \
NV_STORE_INIT_INLINE(); \
} \
} while (0)
/* Attempt to copy to inline storage */
switch (itype) {
case BHND_NVRAM_TYPE_CHAR:
NV_STORE_INLINE(uint8_t, ch);
return (0);
case BHND_NVRAM_TYPE_UINT8:
case BHND_NVRAM_TYPE_INT8:
NV_STORE_INLINE(uint8_t, u8);
return (0);
case BHND_NVRAM_TYPE_UINT16:
case BHND_NVRAM_TYPE_INT16:
NV_STORE_INLINE(uint16_t, u16);
return (0);
case BHND_NVRAM_TYPE_UINT32:
case BHND_NVRAM_TYPE_INT32:
NV_STORE_INLINE(uint32_t, u32);
return (0);
case BHND_NVRAM_TYPE_UINT64:
case BHND_NVRAM_TYPE_INT64:
NV_STORE_INLINE(uint32_t, u32);
return (0);
case BHND_NVRAM_TYPE_CHAR_ARRAY:
NV_COPY_ARRRAY_INLINE(uint8_t, ch);
return (0);
case BHND_NVRAM_TYPE_UINT8_ARRAY:
case BHND_NVRAM_TYPE_INT8_ARRAY:
NV_COPY_ARRRAY_INLINE(uint8_t, u8);
return (0);
case BHND_NVRAM_TYPE_UINT16_ARRAY:
case BHND_NVRAM_TYPE_INT16_ARRAY:
NV_COPY_ARRRAY_INLINE(uint16_t, u16);
return (0);
case BHND_NVRAM_TYPE_UINT32_ARRAY:
case BHND_NVRAM_TYPE_INT32_ARRAY:
NV_COPY_ARRRAY_INLINE(uint32_t, u32);
return (0);
case BHND_NVRAM_TYPE_UINT64_ARRAY:
case BHND_NVRAM_TYPE_INT64_ARRAY:
NV_COPY_ARRRAY_INLINE(uint64_t, u64);
return (0);
case BHND_NVRAM_TYPE_STRING:
case BHND_NVRAM_TYPE_STRING_ARRAY:
if (ilen > sizeof(value->data.ch))
return (ENOMEM);
if (inp != NULL) {
memcpy(&value->data.ch, inp, ilen);
NV_STORE_INIT_INLINE();
}
return (0);
}
#undef NV_STORE_INIT_INLINE
#undef NV_STORE_INLINE
#undef NV_COPY_ARRRAY_INLINE
BHND_NV_PANIC("unknown data type %d", itype);
}
/**
* Initialize the internal representation of @p value with a buffer allocation
* of @p len and @p itype, returning a pointer to the allocated buffer.
*
* If a buffer of @p len and @p itype can be represented inline, no
* external buffer will be allocated, and instead a pointer to the inline
* data representation will be returned.
*
* @param value The value to be initialized.
* @param ilen The size of the external buffer to be allocated.
* @param itype The type of the external buffer to be allocated.
* @param flags Value flags.
*
* @retval non-null The newly allocated buffer.
* @retval NULL If allocation failed.
* @retval NULL If @p value is an externally allocated instance.
*/
static void *
bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
bhnd(4): Unify NVRAM/SPROM parsing, implement compact SPROM layout encoding. - Defined an abstract NVRAM I/O API (bhnd_nvram_io), decoupling NVRAM/SPROM parsing from the actual underlying NVRAM data provider (e.g. CFE firmware devices). - Defined an abstract NVRAM data API (bhnd_nvram_data), decoupling higher-level NVRAM operations (indexed lookup, data conversion, etc) from the underlying NVRAM file format parsing/serialization. - Implemented a new high-level bhnd_nvram_store API, providing indexed variable lookup, pending write tracking, etc on top of an arbitrary bhnd_nvram_data instance. - Migrated all bhnd(4) NVRAM device drivers to the common bhnd_nvram_store API. - Implemented a common bhnd_nvram_val API for parsing/encoding NVRAM variable values, including applying format-specific behavior when converting to/from the NVRAM string representations. - Dropped the now unnecessary bhnd_nvram driver, and moved the broadcom/mips-specific CFE NVRAM driver out into sys/mips/broadcom. - Implemented a new nvram_map file format: - Variable definitions are now defined separately from the SPROM layout. This will also allow us to define CIS tuple NVRAM mappings referencing the common NVRAM variable definitions. - Variables can now be defined within arbitrary named groups. - Textual descriptions and help information can be defined inline for both variables and variable groups. - Implemented a new, compact encoding of SPROM image layout offsets. - Source-level (but not build system) support for building the NVRAM file format APIs (bhnd_nvram_io, bhnd_nvram_data, bhnd_nvram_store) as a userspace library. The new compact SPROM image layout encoding is loosely modeled on Apple dyld compressed LINKEDIT symbol binding opcodes; it provides a compact state-machine encoding of the mapping between NVRAM variables and the SPROM image offset, mask, and shift instructions necessary to decode or encode the SPROM variable data. The compact encoding reduces the size of the generated SPROM layout data from roughly 60KB to 3KB. The sequential nature SPROM layout opcode tables also simplify iteration of the SPROM variables, as it's no longer neccessary to iterate the full NVRAM variable definition table, but instead simply scan the SPROM revision's layout opcode table. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8645
2016-11-26 23:22:32 +00:00
bhnd_nvram_type itype, uint32_t flags)
{
void *ptr;
BHND_NVRAM_VAL_ASSERT_EMPTY(value);
/* Can we use inline storage? */
if (bhnd_nvram_val_set_inline(value, NULL, ilen, itype) == 0) {
BHND_NV_ASSERT(sizeof(value->data) >= ilen,
("ilen exceeds inline storage"));
value->data_type = itype;
value->data_len = ilen;
value->data_storage = BHND_NVRAM_VAL_DATA_INLINE;
return (&value->data);
}
/* Is allocation permitted? */
if (!(flags & BHND_NVRAM_VAL_DYNAMIC))
return (NULL);
/* Allocate external storage */
if ((ptr = bhnd_nv_malloc(ilen)) == NULL)
return (NULL);
value->data.ptr = ptr;
value->data_len = ilen;
value->data_type = itype;
value->data_storage = BHND_NVRAM_VAL_DATA_EXT_ALLOC;
return (ptr);
}