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 */
57 extern const uint8_t bhnd_nvram_crc8_tab[];
58
59 /* Forward declarations */
60 struct bhnd_nvram_vardefn;
61
62 #ifdef _KERNEL
63
64 MALLOC_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 */
85 static inline char *
bhnd_nv_strdup(const char * str)86 bhnd_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 */
103 static inline char *
bhnd_nv_strndup(const char * str,size_t len)104 bhnd_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
189 static inline uintmax_t
bhnd_nv_ummax(uintmax_t a,uintmax_t b)190 bhnd_nv_ummax(uintmax_t a, uintmax_t b)
191 {
192 return (a > b ? a : b);
193 }
194
195 static inline uintmax_t
bhnd_nv_ummin(uintmax_t a,uintmax_t b)196 bhnd_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
215 int 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
220 int bhnd_nvram_value_check_aligned(const void *inp,
221 size_t ilen, bhnd_nvram_type itype);
222
223 int bhnd_nvram_value_nelem(const void *inp,
224 size_t ilen, bhnd_nvram_type itype,
225 size_t *nelem);
226
227 size_t bhnd_nvram_value_size(const void *inp,
228 size_t ilen, bhnd_nvram_type itype,
229 size_t nelem);
230
231 int 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, ...);
235 int 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
240 const 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
244 const struct bhnd_nvram_vardefn *bhnd_nvram_find_vardefn(const char *varname);
245 const struct bhnd_nvram_vardefn *bhnd_nvram_get_vardefn(size_t id);
246 size_t bhnd_nvram_get_vardefn_id(
247 const struct bhnd_nvram_vardefn *defn);
248
249 int 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
254 int 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
259 size_t bhnd_nvram_parse_field(const char **inp,
260 size_t ilen, char delim);
261 size_t bhnd_nvram_trim_field(const char **inp,
262 size_t ilen, char delim);
263
264 const char *bhnd_nvram_trim_path_name(const char *name);
265
266 bool 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 */
276 static inline uint8_t
bhnd_nvram_crc8(const void * buf,size_t size,uint8_t crc)277 bhnd_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 */
290 enum {
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 */
300 enum {
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 */
313 struct 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 */
329 extern const struct bhnd_nvram_vardefn bhnd_nvram_vardefns[];
330 extern const size_t bhnd_nvram_num_vardefns;
331
332 /**
333 * SPROM layout descriptor.
334 */
335 typedef 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 */
353 extern const struct bhnd_sprom_layout bhnd_sprom_layouts[];
354 extern 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