Path: blob/main/sys/dev/bhnd/nvram/bhnd_nvram_private.h
39536 views
/*-1* Copyright (c) 2015-2016 Landon Fuller <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer,9* without modification.10* 2. Redistributions in binary form must reproduce at minimum a disclaimer11* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any12* redistribution must be conditioned upon including a substantially13* similar Disclaimer requirement for further binary redistribution.14*15* NO WARRANTY16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY19* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL20* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,21* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS23* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER24* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)25* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF26* THE POSSIBILITY OF SUCH DAMAGES.27*28*/2930#ifndef _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_31#define _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_3233/*34* Private BHND NVRAM definitions.35*/3637#include <sys/param.h>3839#ifdef _KERNEL40#include <sys/malloc.h>41#include <sys/stdarg.h>42#else43#include <stdarg.h>44#include <stdbool.h>45#include <stdint.h>46#include <stdlib.h>47#endif4849#include "bhnd_nvram.h"50#include "bhnd_nvram_value.h"5152/*53* bhnd_nvram_crc8() lookup table.54*/55extern const uint8_t bhnd_nvram_crc8_tab[];5657/* Forward declarations */58struct bhnd_nvram_vardefn;5960#ifdef _KERNEL6162MALLOC_DECLARE(M_BHND_NVRAM);6364#define bhnd_nv_isupper(c) isupper(c)65#define bhnd_nv_islower(c) islower(c)66#define bhnd_nv_isalpha(c) isalpha(c)67#define bhnd_nv_isprint(c) isprint(c)68#define bhnd_nv_isspace(c) isspace(c)69#define bhnd_nv_isdigit(c) isdigit(c)70#define bhnd_nv_isxdigit(c) isxdigit(c)71#define bhnd_nv_toupper(c) toupper(c)7273#define bhnd_nv_malloc(size) malloc((size), M_BHND_NVRAM, M_NOWAIT)74#define bhnd_nv_calloc(n, size) mallocarray((n), (size), M_BHND_NVRAM, \75M_NOWAIT | M_ZERO)76#define bhnd_nv_reallocf(buf, size) reallocf((buf), (size), M_BHND_NVRAM, \77M_NOWAIT)78#define bhnd_nv_free(buf) free((buf), M_BHND_NVRAM)79#define bhnd_nv_asprintf(buf, fmt, ...) asprintf((buf), M_BHND_NVRAM, \80fmt, ## __VA_ARGS__)8182/* We need our own strdup() implementation to pass required M_NOWAIT */83static inline char *84bhnd_nv_strdup(const char *str)85{86char *dest;87size_t len;8889len = strlen(str);90dest = malloc(len + 1, M_BHND_NVRAM, M_NOWAIT);91if (dest == NULL)92return (NULL);9394memcpy(dest, str, len);95dest[len] = '\0';9697return (dest);98}99100/* We need our own strndup() implementation to pass required M_NOWAIT */101static inline char *102bhnd_nv_strndup(const char *str, size_t len)103{104char *dest;105106len = strnlen(str, len);107dest = malloc(len + 1, M_BHND_NVRAM, M_NOWAIT);108if (dest == NULL)109return (NULL);110111memcpy(dest, str, len);112dest[len] = '\0';113114return (dest);115}116117#ifdef INVARIANTS118#define BHND_NV_INVARIANTS119#endif120121#define BHND_NV_ASSERT(expr, ...) KASSERT(expr, __VA_ARGS__)122123#define BHND_NV_VERBOSE (bootverbose)124#define BHND_NV_PANIC(...) panic(__VA_ARGS__)125#define BHND_NV_LOG(fmt, ...) \126printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)127128#define bhnd_nv_ummax(a, b) ummax((a), (b))129#define bhnd_nv_ummin(a, b) ummin((a), (b))130131#else /* !_KERNEL */132133#include <assert.h>134#include <stdint.h>135#include <stdio.h>136#include <stdlib.h>137138/* ASCII-specific ctype variants that work consistently regardless139* of current locale */140#define bhnd_nv_isupper(c) ((c) >= 'A' && (c) <= 'Z')141#define bhnd_nv_islower(c) ((c) >= 'a' && (c) <= 'z')142#define bhnd_nv_isalpha(c) (bhnd_nv_isupper(c) || bhnd_nv_islower(c))143#define bhnd_nv_isprint(c) ((c) >= ' ' && (c) <= '~')144#define bhnd_nv_isspace(c) ((c) == ' ' || ((c) >= '\t' && (c) <= '\r'))145#define bhnd_nv_isdigit(c) isdigit(c)146#define bhnd_nv_isxdigit(c) isxdigit(c)147#define bhnd_nv_toupper(c) ((c) - \148(('a' - 'A') * ((c) >= 'a' && (c) <= 'z')))149150#define bhnd_nv_malloc(size) malloc((size))151#define bhnd_nv_calloc(n, size) calloc((n), (size))152#define bhnd_nv_reallocf(buf, size) reallocf((buf), (size))153#define bhnd_nv_free(buf) free((buf))154#define bhnd_nv_strdup(str) strdup(str)155#define bhnd_nv_strndup(str, len) strndup(str, len)156#define bhnd_nv_asprintf(buf, fmt, ...) asprintf((buf), fmt, ## __VA_ARGS__)157158#ifndef NDEBUG159#define BHND_NV_INVARIANTS160#endif161162#ifdef BHND_NV_INVARIANTS163164#define BHND_NV_ASSERT(expr, msg) do { \165if (!(expr)) { \166fprintf(stderr, "Assertion failed: %s, function %s, " \167"file %s, line %u\n", __STRING(expr), __FUNCTION__, \168__FILE__, __LINE__); \169BHND_NV_PANIC msg; \170} \171} while(0)172173#else /* !BHND_NV_INVARIANTS */174175#define BHND_NV_ASSERT(expr, msg)176177#endif /* BHND_NV_INVARIANTS */178179#define BHND_NV_VERBOSE (0)180#define BHND_NV_PANIC(fmt, ...) do { \181fprintf(stderr, "panic: " fmt "\n", ##__VA_ARGS__); \182abort(); \183} while(0)184#define BHND_NV_LOG(fmt, ...) \185fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)186187static inline uintmax_t188bhnd_nv_ummax(uintmax_t a, uintmax_t b)189{190return (a > b ? a : b);191}192193static inline uintmax_t194bhnd_nv_ummin(uintmax_t a, uintmax_t b)195{196197return (a < b ? a : b);198}199200#endif /* _KERNEL */201202#ifdef BHND_NV_VERBOSE203#define BHND_NV_DEBUG(...) BHND_NV_LOG(__VA_ARGS__)204#else /* !BHND_NV_VERBOSE */205#define BHND_NV_DEBUG(...)206#endif /* BHND_NV_VERBOSE */207208/* Limit a size_t value to a suitable range for use as a printf string field209* width */210#define BHND_NV_PRINT_WIDTH(_len) \211((_len) > (INT_MAX) ? (INT_MAX) : (int)(_len))212213int bhnd_nvram_value_coerce(const void *inp,214size_t ilen, bhnd_nvram_type itype,215void *outp, size_t *olen,216bhnd_nvram_type otype);217218int bhnd_nvram_value_check_aligned(const void *inp,219size_t ilen, bhnd_nvram_type itype);220221int bhnd_nvram_value_nelem(const void *inp,222size_t ilen, bhnd_nvram_type itype,223size_t *nelem);224225size_t bhnd_nvram_value_size(const void *inp,226size_t ilen, bhnd_nvram_type itype,227size_t nelem);228229int bhnd_nvram_value_printf(const char *fmt,230const void *inp, size_t ilen,231bhnd_nvram_type itype, char *outp,232size_t *olen, ...);233int bhnd_nvram_value_vprintf(const char *fmt,234const void *inp, size_t ilen,235bhnd_nvram_type itype, char *outp,236size_t *olen, va_list ap);237238const void *bhnd_nvram_value_array_next(const void *inp,239size_t ilen, bhnd_nvram_type itype,240const void *prev, size_t *olen);241242const struct bhnd_nvram_vardefn *bhnd_nvram_find_vardefn(const char *varname);243const struct bhnd_nvram_vardefn *bhnd_nvram_get_vardefn(size_t id);244size_t bhnd_nvram_get_vardefn_id(245const struct bhnd_nvram_vardefn *defn);246247int bhnd_nvram_parse_int(const char *s,248size_t maxlen, u_int base, size_t *nbytes,249void *outp, size_t *olen,250bhnd_nvram_type otype);251252int bhnd_nvram_parse_env(const char *env,253size_t env_len, char delim,254const char **name, size_t *name_len,255const char **value, size_t *value_len);256257size_t bhnd_nvram_parse_field(const char **inp,258size_t ilen, char delim);259size_t bhnd_nvram_trim_field(const char **inp,260size_t ilen, char delim);261262const char *bhnd_nvram_trim_path_name(const char *name);263264bool bhnd_nvram_validate_name(const char *name);265266/**267* Calculate CRC-8 over @p buf using the Broadcom SPROM/NVRAM CRC-8268* polynomial.269*270* @param buf input buffer271* @param size buffer size272* @param crc last computed crc, or BHND_NVRAM_CRC8_INITIAL273*/274static inline uint8_t275bhnd_nvram_crc8(const void *buf, size_t size, uint8_t crc)276{277const uint8_t *p = (const uint8_t *)buf;278while (size--)279crc = bhnd_nvram_crc8_tab[(crc ^ *p++)];280281return (crc);282}283284#define BHND_NVRAM_CRC8_INITIAL 0xFF /**< Initial bhnd_nvram_crc8 value */285#define BHND_NVRAM_CRC8_VALID 0x9F /**< Valid CRC-8 checksum */286287/** NVRAM variable flags */288enum {289BHND_NVRAM_VF_MFGINT = 1<<0, /**< mfg-internal variable; should not290be externally visible */291BHND_NVRAM_VF_IGNALL1 = 1<<1 /**< hide variable if its value has all292bits set. */293};294295/**296* SPROM layout flags297*/298enum {299/**300* SPROM layout does not have magic identification value.301*302* This applies to SPROM revisions 1-3, where the actual303* layout must be determined by looking for a matching sromrev304* at the expected offset, and then verifying the CRC to ensure305* that the match was not a false positive.306*/307SPROM_LAYOUT_MAGIC_NONE = (1<<0),308};309310/** NVRAM variable definition */311struct bhnd_nvram_vardefn {312const char *name; /**< variable name */313const char *desc; /**< human readable description,314or NULL */315const char *help; /**< human readable help text,316or NULL */317bhnd_nvram_type type; /**< variable type */318uint8_t nelem; /**< element count, or 1 if not319an array-typed variable */320const bhnd_nvram_val_fmt *fmt; /**< value format */321uint32_t flags; /**< flags (BHND_NVRAM_VF_*) */322};323324/*325* NVRAM variable definitions generated from nvram_map.326*/327extern const struct bhnd_nvram_vardefn bhnd_nvram_vardefns[];328extern const size_t bhnd_nvram_num_vardefns;329330/**331* SPROM layout descriptor.332*/333typedef struct bhnd_sprom_layout {334size_t size; /**< SPROM image size, in bytes */335uint8_t rev; /**< SPROM revision */336uint8_t flags; /**< layout flags (SPROM_LAYOUT_*) */337size_t srev_offset; /**< offset to SROM revision */338size_t magic_offset; /**< offset to magic value */339uint16_t magic_value; /**< expected magic value */340size_t crc_offset; /**< offset to crc8 value */341const uint8_t *bindings; /**< SPROM binding opcode table */342size_t bindings_size; /**< SPROM binding opcode table size */343uint16_t num_vars; /**< total number of variables defined344for this layout by the binding345table */346} bhnd_sprom_layout;347348/*349* SPROM layout descriptions generated from nvram_map.350*/351extern const struct bhnd_sprom_layout bhnd_sprom_layouts[];352extern const size_t bhnd_sprom_num_layouts;353354/*355* SPROM binding opcodes.356*357* Most opcodes are provided with two variants:358*359* - Standard: The opcode's data directly follows the opcode. The data type360* (SPROM_OPCODE_DATA_*) is encoded in the opcode immediate (IMM).361* - Immediate: The opcode's data is encoded directly in the opcode immediate362* (IMM).363*/364#define SPROM_OPC_MASK 0xF0 /**< operation mask */365#define SPROM_IMM_MASK 0x0F /**< immediate value mask */366#define SPROM_IMM_MAX SPROM_IMM_MASK367#define SPROM_OP_DATA_U8 0x00 /**< data is u8 */368#define SPROM_OP_DATA_U8_SCALED 0x01 /**< data is u8; multiply by369type width */370#define SPROM_OP_DATA_U16 0x02 /**< data is u16-le */371#define SPROM_OP_DATA_U32 0x03 /**< data is u32-le */372#define SPROM_OP_DATA_I8 0x04 /**< data is i8 */373#define SPROM_OPCODE_EXT 0x00 /**< extended opcodes defined374in IMM */375#define SPROM_OPCODE_EOF 0x00 /**< marks end of opcode376stream */377#define SPROM_OPCODE_NELEM 0x01 /**< variable array element378count follows as U8 */379#define SPROM_OPCODE_VAR_END 0x02 /**< marks end of variable380definition */381#define SPROM_OPCODE_TYPE 0x03 /**< input type follows as U8382(see BHND_NVRAM_TYPE_*) */383#define SPROM_OPCODE_VAR_IMM 0x10 /**< variable ID (imm) */384#define SPROM_OPCODE_VAR_REL_IMM 0x20 /**< relative variable ID385(last ID + imm) */386#define SPROM_OPCODE_VAR 0x30 /**< variable ID */387#define SPROM_OPCODE_REV_IMM 0x40 /**< revision range (imm) */388#define SPROM_OPCODE_REV_RANGE 0x50 /**< revision range (8-bit range)*/389#define SPROM_OP_REV_RANGE_MAX 0x0F /**< maximum representable SROM390revision */391#define SPROM_OP_REV_START_MASK 0xF0392#define SPROM_OP_REV_START_SHIFT 4393#define SPROM_OP_REV_END_MASK 0x0F394#define SPROM_OP_REV_END_SHIFT 0395#define SPROM_OPCODE_MASK_IMM 0x60 /**< value mask (imm) */396#define SPROM_OPCODE_MASK 0x70 /**< value mask */397#define SPROM_OPCODE_SHIFT_IMM 0x80 /**< value shift (unsigned398imm, multipled by 2) */399#define SPROM_OPCODE_SHIFT 0x90 /**< value shift */400#define SPROM_OPCODE_OFFSET_REL_IMM 0xA0 /**< relative input offset401(last offset +402(imm * type width)) */403#define SPROM_OPCODE_OFFSET 0xB0 /**< input offset */404#define SPROM_OPCODE_TYPE_IMM 0xC0 /**< input type (imm,405see BHND_NVRAM_TYPE_*) */406#define SPROM_OPCODE_DO_BIND 0xD0 /**< bind current value,407advance input/output408offsets as per IMM */409#define SPROM_OP_BIND_SKIP_IN_MASK 0x03 /**< the number of input410elements to advance after411the bind */412#define SPROM_OP_BIND_SKIP_IN_SHIFT 0413#define SPROM_OP_BIND_SKIP_IN_SIGN (1<<2) /**< SKIP_IN sign bit */414#define SPROM_OP_BIND_SKIP_OUT_MASK 0x08 /**< the number of output415elements to advance after416the bind */417#define SPROM_OP_BIND_SKIP_OUT_SHIFT 3418#define SPROM_OPCODE_DO_BINDN_IMM 0xE0 /**< bind IMM times, advancing419input/output offsets by one420element each time */421#define SPROM_OPCODE_DO_BINDN 0xF0 /**< bind N times, advancing422input/output offsets as per423SPROM_OP_BIND_SKIP_IN/SPROM_OP_BIND_SKIP_OUT424IMM values. The U8 element425count follows. */426427/** Evaluates to true if opcode is an extended opcode */428#define SPROM_OPCODE_IS_EXT(_opcode) \429(((_opcode) & SPROM_OPC_MASK) == SPROM_OPCODE_EXT)430431/** Return the opcode constant for a simple or extended opcode */432#define SPROM_OPCODE_OP(_opcode) \433(SPROM_OPCODE_IS_EXT(_opcode) ? (_opcode) : ((_opcode) & SPROM_OPC_MASK))434435/** Return the opcode immediate for a simple opcode, or zero if this is436* an extended opcode */437#define SPROM_OPCODE_IMM(_opcode) \438(SPROM_OPCODE_IS_EXT(_opcode) ? 0 : ((_opcode) & SPROM_IMM_MASK))439440/** Evaluates to true if the given opcode produces an implicit441* SPROM_OPCODE_VAR_END instruction for any open variable */442#define SPROM_OP_IS_IMPLICIT_VAR_END(_opcode) \443(((_opcode) == SPROM_OPCODE_VAR_IMM) || \444((_opcode) == SPROM_OPCODE_VAR_REL_IMM) || \445((_opcode) == SPROM_OPCODE_VAR) || \446((_opcode) == SPROM_OPCODE_REV_IMM) || \447((_opcode) == SPROM_OPCODE_REV_RANGE))448449/** Evaluates to true if the given opcode is either an explicit450* SPROM_OPCODE_VAR_END instruction, or is an opcode that produces an451* implicit terminatation of any open variable */452#define SPROM_OP_IS_VAR_END(_opcode) \453(((_opcode) == SPROM_OPCODE_VAR_END) || \454SPROM_OP_IS_IMPLICIT_VAR_END(_opcode))455456/** maximum representable immediate value */457#define SPROM_OP_IMM_MAX SPROM_IMM_MASK458459/** maximum representable SROM revision */460#define SPROM_OP_REV_MAX MAX(SPROM_OP_REV_RANGE_MAX, SPROM_IMM_MAX)461462#endif /* _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_ */463464465