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