1/*- 2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 * 29 */ 30 31#ifndef _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_ 32#define _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_ 33 34/* 35 * Private BHND NVRAM definitions. 36 */ 37 38#include <sys/param.h> 39 40#ifdef _KERNEL 41#include <sys/malloc.h> 42 43#include <machine/stdarg.h> 44#else 45#include <stdarg.h> 46#include <stdbool.h> 47#include <stdint.h> 48#include <stdlib.h> 49#endif 50 51#include "bhnd_nvram.h" 52#include "bhnd_nvram_value.h" 53 54/* 55 * bhnd_nvram_crc8() lookup table. 56 */ 57extern const uint8_t bhnd_nvram_crc8_tab[]; 58 59/* Forward declarations */ 60struct bhnd_nvram_vardefn; 61 62#ifdef _KERNEL 63 64MALLOC_DECLARE(M_BHND_NVRAM); 65 66#define bhnd_nv_isupper(c) isupper(c) 67#define bhnd_nv_islower(c) islower(c) 68#define bhnd_nv_isalpha(c) isalpha(c) 69#define bhnd_nv_isprint(c) isprint(c) 70#define bhnd_nv_isspace(c) isspace(c) 71#define bhnd_nv_isdigit(c) isdigit(c) 72#define bhnd_nv_isxdigit(c) isxdigit(c) 73#define bhnd_nv_toupper(c) toupper(c) 74 75#define bhnd_nv_malloc(size) malloc((size), M_BHND_NVRAM, M_NOWAIT) 76#define bhnd_nv_calloc(n, size) mallocarray((n), (size), M_BHND_NVRAM, \ 77 M_NOWAIT | M_ZERO) 78#define bhnd_nv_reallocf(buf, size) reallocf((buf), (size), M_BHND_NVRAM, \ 79 M_NOWAIT) 80#define bhnd_nv_free(buf) free((buf), M_BHND_NVRAM) 81#define bhnd_nv_asprintf(buf, fmt, ...) asprintf((buf), M_BHND_NVRAM, \ 82 fmt, ## __VA_ARGS__) 83 84/* We need our own strdup() implementation to pass required M_NOWAIT */ 85static inline char * 86bhnd_nv_strdup(const char *str) 87{ 88 char *dest; 89 size_t len; 90 91 len = strlen(str); 92 dest = malloc(len + 1, M_BHND_NVRAM, M_NOWAIT); 93 if (dest == NULL) 94 return (NULL); 95 96 memcpy(dest, str, len); 97 dest[len] = '\0'; 98 99 return (dest); 100} 101 102/* We need our own strndup() implementation to pass required M_NOWAIT */ 103static inline char * 104bhnd_nv_strndup(const char *str, size_t len) 105{ 106 char *dest; 107 108 len = strnlen(str, len); 109 dest = malloc(len + 1, M_BHND_NVRAM, M_NOWAIT); 110 if (dest == NULL) 111 return (NULL); 112 113 memcpy(dest, str, len); 114 dest[len] = '\0'; 115 116 return (dest); 117} 118 119#ifdef INVARIANTS 120#define BHND_NV_INVARIANTS 121#endif 122 123#define BHND_NV_ASSERT(expr, ...) KASSERT(expr, __VA_ARGS__) 124 125#define BHND_NV_VERBOSE (bootverbose) 126#define BHND_NV_PANIC(...) panic(__VA_ARGS__) 127#define BHND_NV_LOG(fmt, ...) \ 128 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__) 129 130#define bhnd_nv_ummax(a, b) ummax((a), (b)) 131#define bhnd_nv_ummin(a, b) ummin((a), (b)) 132 133#else /* !_KERNEL */ 134 135#include <assert.h> 136#include <stdint.h> 137#include <stdio.h> 138#include <stdlib.h> 139 140/* ASCII-specific ctype variants that work consistently regardless 141 * of current locale */ 142#define bhnd_nv_isupper(c) ((c) >= 'A' && (c) <= 'Z') 143#define bhnd_nv_islower(c) ((c) >= 'a' && (c) <= 'z') 144#define bhnd_nv_isalpha(c) (bhnd_nv_isupper(c) || bhnd_nv_islower(c)) 145#define bhnd_nv_isprint(c) ((c) >= ' ' && (c) <= '~') 146#define bhnd_nv_isspace(c) ((c) == ' ' || ((c) >= '\t' && (c) <= '\r')) 147#define bhnd_nv_isdigit(c) isdigit(c) 148#define bhnd_nv_isxdigit(c) isxdigit(c) 149#define bhnd_nv_toupper(c) ((c) - \ 150 (('a' - 'A') * ((c) >= 'a' && (c) <= 'z'))) 151 152#define bhnd_nv_malloc(size) malloc((size)) 153#define bhnd_nv_calloc(n, size) calloc((n), (size)) 154#define bhnd_nv_reallocf(buf, size) reallocf((buf), (size)) 155#define bhnd_nv_free(buf) free((buf)) 156#define bhnd_nv_strdup(str) strdup(str) 157#define bhnd_nv_strndup(str, len) strndup(str, len) 158#define bhnd_nv_asprintf(buf, fmt, ...) asprintf((buf), fmt, ## __VA_ARGS__) 159 160#ifndef NDEBUG 161#define BHND_NV_INVARIANTS 162#endif 163 164#ifdef BHND_NV_INVARIANTS 165 166#define BHND_NV_ASSERT(expr, msg) do { \ 167 if (!(expr)) { \ 168 fprintf(stderr, "Assertion failed: %s, function %s, " \ 169 "file %s, line %u\n", __STRING(expr), __FUNCTION__, \ 170 __FILE__, __LINE__); \ 171 BHND_NV_PANIC msg; \ 172 } \ 173} while(0) 174 175#else /* !BHND_NV_INVARIANTS */ 176 177#define BHND_NV_ASSERT(expr, msg) 178 179#endif /* BHND_NV_INVARIANTS */ 180 181#define BHND_NV_VERBOSE (0) 182#define BHND_NV_PANIC(fmt, ...) do { \ 183 fprintf(stderr, "panic: " fmt "\n", ##__VA_ARGS__); \ 184 abort(); \ 185} while(0) 186#define BHND_NV_LOG(fmt, ...) \ 187 fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__) 188 189static inline uintmax_t 190bhnd_nv_ummax(uintmax_t a, uintmax_t b) 191{ 192 return (a > b ? a : b); 193} 194 195static inline uintmax_t 196bhnd_nv_ummin(uintmax_t a, uintmax_t b) 197{ 198 199 return (a < b ? a : b); 200} 201 202#endif /* _KERNEL */ 203 204#ifdef BHND_NV_VERBOSE 205#define BHND_NV_DEBUG(...) BHND_NV_LOG(__VA_ARGS__) 206#else /* !BHND_NV_VERBOSE */ 207#define BHND_NV_DEBUG(...) 208#endif /* BHND_NV_VERBOSE */ 209 210/* Limit a size_t value to a suitable range for use as a printf string field 211 * width */ 212#define BHND_NV_PRINT_WIDTH(_len) \ 213 ((_len) > (INT_MAX) ? (INT_MAX) : (int)(_len)) 214 215int bhnd_nvram_value_coerce(const void *inp, 216 size_t ilen, bhnd_nvram_type itype, 217 void *outp, size_t *olen, 218 bhnd_nvram_type otype); 219 220int bhnd_nvram_value_check_aligned(const void *inp, 221 size_t ilen, bhnd_nvram_type itype); 222 223int bhnd_nvram_value_nelem(const void *inp, 224 size_t ilen, bhnd_nvram_type itype, 225 size_t *nelem); 226 227size_t bhnd_nvram_value_size(const void *inp, 228 size_t ilen, bhnd_nvram_type itype, 229 size_t nelem); 230 231int bhnd_nvram_value_printf(const char *fmt, 232 const void *inp, size_t ilen, 233 bhnd_nvram_type itype, char *outp, 234 size_t *olen, ...); 235int bhnd_nvram_value_vprintf(const char *fmt, 236 const void *inp, size_t ilen, 237 bhnd_nvram_type itype, char *outp, 238 size_t *olen, va_list ap); 239 240const void *bhnd_nvram_value_array_next(const void *inp, 241 size_t ilen, bhnd_nvram_type itype, 242 const void *prev, size_t *olen); 243 244const struct bhnd_nvram_vardefn *bhnd_nvram_find_vardefn(const char *varname); 245const struct bhnd_nvram_vardefn *bhnd_nvram_get_vardefn(size_t id); 246size_t bhnd_nvram_get_vardefn_id( 247 const struct bhnd_nvram_vardefn *defn); 248 249int bhnd_nvram_parse_int(const char *s, 250 size_t maxlen, u_int base, size_t *nbytes, 251 void *outp, size_t *olen, 252 bhnd_nvram_type otype); 253 254int bhnd_nvram_parse_env(const char *env, 255 size_t env_len, char delim, 256 const char **name, size_t *name_len, 257 const char **value, size_t *value_len); 258 259size_t bhnd_nvram_parse_field(const char **inp, 260 size_t ilen, char delim); 261size_t bhnd_nvram_trim_field(const char **inp, 262 size_t ilen, char delim); 263 264const char *bhnd_nvram_trim_path_name(const char *name); 265 266bool bhnd_nvram_validate_name(const char *name); 267 268/** 269 * Calculate CRC-8 over @p buf using the Broadcom SPROM/NVRAM CRC-8 270 * polynomial. 271 * 272 * @param buf input buffer 273 * @param size buffer size 274 * @param crc last computed crc, or BHND_NVRAM_CRC8_INITIAL 275 */ 276static inline uint8_t 277bhnd_nvram_crc8(const void *buf, size_t size, uint8_t crc) 278{ 279 const uint8_t *p = (const uint8_t *)buf; 280 while (size--) 281 crc = bhnd_nvram_crc8_tab[(crc ^ *p++)]; 282 283 return (crc); 284} 285 286#define BHND_NVRAM_CRC8_INITIAL 0xFF /**< Initial bhnd_nvram_crc8 value */ 287#define BHND_NVRAM_CRC8_VALID 0x9F /**< Valid CRC-8 checksum */ 288 289/** NVRAM variable flags */ 290enum { 291 BHND_NVRAM_VF_MFGINT = 1<<0, /**< mfg-internal variable; should not 292 be externally visible */ 293 BHND_NVRAM_VF_IGNALL1 = 1<<1 /**< hide variable if its value has all 294 bits set. */ 295}; 296 297/** 298 * SPROM layout flags 299 */ 300enum { 301 /** 302 * SPROM layout does not have magic identification value. 303 * 304 * This applies to SPROM revisions 1-3, where the actual 305 * layout must be determined by looking for a matching sromrev 306 * at the expected offset, and then verifying the CRC to ensure 307 * that the match was not a false positive. 308 */ 309 SPROM_LAYOUT_MAGIC_NONE = (1<<0), 310}; 311 312/** NVRAM variable definition */ 313struct bhnd_nvram_vardefn { 314 const char *name; /**< variable name */ 315 const char *desc; /**< human readable description, 316 or NULL */ 317 const char *help; /**< human readable help text, 318 or NULL */ 319 bhnd_nvram_type type; /**< variable type */ 320 uint8_t nelem; /**< element count, or 1 if not 321 an array-typed variable */ 322 const bhnd_nvram_val_fmt *fmt; /**< value format */ 323 uint32_t flags; /**< flags (BHND_NVRAM_VF_*) */ 324}; 325 326/* 327 * NVRAM variable definitions generated from nvram_map. 328 */ 329extern const struct bhnd_nvram_vardefn bhnd_nvram_vardefns[]; 330extern const size_t bhnd_nvram_num_vardefns; 331 332/** 333 * SPROM layout descriptor. 334 */ 335typedef struct bhnd_sprom_layout { 336 size_t size; /**< SPROM image size, in bytes */ 337 uint8_t rev; /**< SPROM revision */ 338 uint8_t flags; /**< layout flags (SPROM_LAYOUT_*) */ 339 size_t srev_offset; /**< offset to SROM revision */ 340 size_t magic_offset; /**< offset to magic value */ 341 uint16_t magic_value; /**< expected magic value */ 342 size_t crc_offset; /**< offset to crc8 value */ 343 const uint8_t *bindings; /**< SPROM binding opcode table */ 344 size_t bindings_size; /**< SPROM binding opcode table size */ 345 uint16_t num_vars; /**< total number of variables defined 346 for this layout by the binding 347 table */ 348} bhnd_sprom_layout; 349 350/* 351 * SPROM layout descriptions generated from nvram_map. 352 */ 353extern const struct bhnd_sprom_layout bhnd_sprom_layouts[]; 354extern const size_t bhnd_sprom_num_layouts; 355 356/* 357 * SPROM binding opcodes. 358 * 359 * Most opcodes are provided with two variants: 360 * 361 * - Standard: The opcode's data directly follows the opcode. The data type 362 * (SPROM_OPCODE_DATA_*) is encoded in the opcode immediate (IMM). 363 * - Immediate: The opcode's data is encoded directly in the opcode immediate 364 * (IMM). 365 */ 366#define SPROM_OPC_MASK 0xF0 /**< operation mask */ 367#define SPROM_IMM_MASK 0x0F /**< immediate value mask */ 368#define SPROM_IMM_MAX SPROM_IMM_MASK 369#define SPROM_OP_DATA_U8 0x00 /**< data is u8 */ 370#define SPROM_OP_DATA_U8_SCALED 0x01 /**< data is u8; multiply by 371 type width */ 372#define SPROM_OP_DATA_U16 0x02 /**< data is u16-le */ 373#define SPROM_OP_DATA_U32 0x03 /**< data is u32-le */ 374#define SPROM_OP_DATA_I8 0x04 /**< data is i8 */ 375#define SPROM_OPCODE_EXT 0x00 /**< extended opcodes defined 376 in IMM */ 377#define SPROM_OPCODE_EOF 0x00 /**< marks end of opcode 378 stream */ 379#define SPROM_OPCODE_NELEM 0x01 /**< variable array element 380 count follows as U8 */ 381#define SPROM_OPCODE_VAR_END 0x02 /**< marks end of variable 382 definition */ 383#define SPROM_OPCODE_TYPE 0x03 /**< input type follows as U8 384 (see BHND_NVRAM_TYPE_*) */ 385#define SPROM_OPCODE_VAR_IMM 0x10 /**< variable ID (imm) */ 386#define SPROM_OPCODE_VAR_REL_IMM 0x20 /**< relative variable ID 387 (last ID + imm) */ 388#define SPROM_OPCODE_VAR 0x30 /**< variable ID */ 389#define SPROM_OPCODE_REV_IMM 0x40 /**< revision range (imm) */ 390#define SPROM_OPCODE_REV_RANGE 0x50 /**< revision range (8-bit range)*/ 391#define SPROM_OP_REV_RANGE_MAX 0x0F /**< maximum representable SROM 392 revision */ 393#define SPROM_OP_REV_START_MASK 0xF0 394#define SPROM_OP_REV_START_SHIFT 4 395#define SPROM_OP_REV_END_MASK 0x0F 396#define SPROM_OP_REV_END_SHIFT 0 397#define SPROM_OPCODE_MASK_IMM 0x60 /**< value mask (imm) */ 398#define SPROM_OPCODE_MASK 0x70 /**< value mask */ 399#define SPROM_OPCODE_SHIFT_IMM 0x80 /**< value shift (unsigned 400 imm, multipled by 2) */ 401#define SPROM_OPCODE_SHIFT 0x90 /**< value shift */ 402#define SPROM_OPCODE_OFFSET_REL_IMM 0xA0 /**< relative input offset 403 (last offset + 404 (imm * type width)) */ 405#define SPROM_OPCODE_OFFSET 0xB0 /**< input offset */ 406#define SPROM_OPCODE_TYPE_IMM 0xC0 /**< input type (imm, 407 see BHND_NVRAM_TYPE_*) */ 408#define SPROM_OPCODE_DO_BIND 0xD0 /**< bind current value, 409 advance input/output 410 offsets as per IMM */ 411#define SPROM_OP_BIND_SKIP_IN_MASK 0x03 /**< the number of input 412 elements to advance after 413 the bind */ 414#define SPROM_OP_BIND_SKIP_IN_SHIFT 0 415#define SPROM_OP_BIND_SKIP_IN_SIGN (1<<2) /**< SKIP_IN sign bit */ 416#define SPROM_OP_BIND_SKIP_OUT_MASK 0x08 /**< the number of output 417 elements to advance after 418 the bind */ 419#define SPROM_OP_BIND_SKIP_OUT_SHIFT 3 420#define SPROM_OPCODE_DO_BINDN_IMM 0xE0 /**< bind IMM times, advancing 421 input/output offsets by one 422 element each time */ 423#define SPROM_OPCODE_DO_BINDN 0xF0 /**< bind N times, advancing 424 input/output offsets as per 425 SPROM_OP_BIND_SKIP_IN/SPROM_OP_BIND_SKIP_OUT 426 IMM values. The U8 element 427 count follows. */ 428 429/** Evaluates to true if opcode is an extended opcode */ 430#define SPROM_OPCODE_IS_EXT(_opcode) \ 431 (((_opcode) & SPROM_OPC_MASK) == SPROM_OPCODE_EXT) 432 433/** Return the opcode constant for a simple or extended opcode */ 434#define SPROM_OPCODE_OP(_opcode) \ 435 (SPROM_OPCODE_IS_EXT(_opcode) ? (_opcode) : ((_opcode) & SPROM_OPC_MASK)) 436 437/** Return the opcode immediate for a simple opcode, or zero if this is 438 * an extended opcode */ 439#define SPROM_OPCODE_IMM(_opcode) \ 440 (SPROM_OPCODE_IS_EXT(_opcode) ? 0 : ((_opcode) & SPROM_IMM_MASK)) 441 442/** Evaluates to true if the given opcode produces an implicit 443 * SPROM_OPCODE_VAR_END instruction for any open variable */ 444#define SPROM_OP_IS_IMPLICIT_VAR_END(_opcode) \ 445 (((_opcode) == SPROM_OPCODE_VAR_IMM) || \ 446 ((_opcode) == SPROM_OPCODE_VAR_REL_IMM) || \ 447 ((_opcode) == SPROM_OPCODE_VAR) || \ 448 ((_opcode) == SPROM_OPCODE_REV_IMM) || \ 449 ((_opcode) == SPROM_OPCODE_REV_RANGE)) 450 451/** Evaluates to true if the given opcode is either an explicit 452 * SPROM_OPCODE_VAR_END instruction, or is an opcode that produces an 453 * implicit terminatation of any open variable */ 454#define SPROM_OP_IS_VAR_END(_opcode) \ 455 (((_opcode) == SPROM_OPCODE_VAR_END) || \ 456 SPROM_OP_IS_IMPLICIT_VAR_END(_opcode)) 457 458/** maximum representable immediate value */ 459#define SPROM_OP_IMM_MAX SPROM_IMM_MASK 460 461/** maximum representable SROM revision */ 462#define SPROM_OP_REV_MAX MAX(SPROM_OP_REV_RANGE_MAX, SPROM_IMM_MAX) 463 464#endif /* _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_ */ 465