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