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