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#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/param.h>
34
35#ifdef _KERNEL
36
37#include <sys/ctype.h>
38#include <sys/kernel.h>
39#include <sys/limits.h>
40#include <sys/malloc.h>
41#include <sys/systm.h>
42
43#include <machine/_inttypes.h>
44
45#else /* !_KERNEL */
46
47#include <ctype.h>
48#include <errno.h>
49#include <inttypes.h>
50#include <limits.h>
51#include <stdbool.h>
52#include <stdio.h>
53#include <stdint.h>
54#include <stdlib.h>
55#include <string.h>
56
57#endif /* _KERNEL */
58
59#include "bhnd_nvram_io.h"
60#include "bhnd_nvram_private.h"
61#include "bhnd_nvram_value.h"
62
63#include "bhnd_nvram_map_data.h"
64
65/*
66 * Common NVRAM/SPROM support, including NVRAM variable map
67 * lookup.
68 */
69
70#ifdef _KERNEL
71MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data");
72#endif
73
74/*
75 * CRC-8 lookup table used to checksum SPROM and NVRAM data via
76 * bhnd_nvram_crc8().
77 *
78 * Generated with following parameters:
79 * 	polynomial:	CRC-8 (x^8 + x^7 + x^6 + x^4 + x^2 + 1)
80 * 	reflected bits:	false
81 * 	reversed:	true
82 */
83const uint8_t bhnd_nvram_crc8_tab[] = {
84	0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b, 0x4a, 0xbd, 0xf3,
85	0x04, 0x6f, 0x98, 0xd6, 0x21, 0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46,
86	0x08, 0xff, 0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5, 0x7f,
87	0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14, 0x35, 0xc2, 0x8c, 0x7b,
88	0x10, 0xe7, 0xa9, 0x5e, 0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77,
89	0x80, 0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca, 0xfe, 0x09,
90	0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95, 0xb4, 0x43, 0x0d, 0xfa, 0x91,
91	0x66, 0x28, 0xdf, 0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01,
92	0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b, 0x81, 0x76, 0x38,
93	0xcf, 0xa4, 0x53, 0x1d, 0xea, 0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19,
94	0x57, 0xa0, 0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e, 0x5f,
95	0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34, 0xab, 0x5c, 0x12, 0xe5,
96	0x8e, 0x79, 0x37, 0xc0, 0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d,
97	0x8a, 0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54, 0x75, 0x82,
98	0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e, 0xd4, 0x23, 0x6d, 0x9a, 0xf1,
99	0x06, 0x48, 0xbf, 0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5,
100	0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b, 0x0a, 0xfd, 0xb3,
101	0x44, 0x2f, 0xd8, 0x96, 0x61, 0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87,
102	0xc9, 0x3e, 0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74, 0xc1,
103	0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa, 0x8b, 0x7c, 0x32, 0xc5,
104	0xae, 0x59, 0x17, 0xe0, 0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6,
105	0x41, 0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b, 0xbe, 0x49,
106	0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5, 0xf4, 0x03, 0x4d, 0xba, 0xd1,
107	0x26, 0x68, 0x9f
108};
109
110/**
111 * Return a human readable name for @p type.
112 *
113 * @param type The type to query.
114 */
115const char *
116bhnd_nvram_type_name(bhnd_nvram_type type)
117{
118	switch (type) {
119	case BHND_NVRAM_TYPE_UINT8:
120		return ("uint8");
121	case BHND_NVRAM_TYPE_UINT16:
122		return ("uint16");
123	case BHND_NVRAM_TYPE_UINT32:
124		return ("uint32");
125	case BHND_NVRAM_TYPE_UINT64:
126		return ("uint64");
127	case BHND_NVRAM_TYPE_CHAR:
128		return ("char");
129	case BHND_NVRAM_TYPE_INT8:
130		return ("int8");
131	case BHND_NVRAM_TYPE_INT16:
132		return ("int16");
133	case BHND_NVRAM_TYPE_INT32:
134		return ("int32");
135	case BHND_NVRAM_TYPE_INT64:
136		return ("int64");
137	case BHND_NVRAM_TYPE_STRING:
138		return ("string");
139	case BHND_NVRAM_TYPE_BOOL:
140		return ("bool");
141	case BHND_NVRAM_TYPE_NULL:
142		return ("null");
143	case BHND_NVRAM_TYPE_DATA:
144		return ("data");
145	case BHND_NVRAM_TYPE_UINT8_ARRAY:
146		return ("uint8[]");
147	case BHND_NVRAM_TYPE_UINT16_ARRAY:
148		return ("uint16[]");
149	case BHND_NVRAM_TYPE_UINT32_ARRAY:
150		return ("uint32[]");
151	case BHND_NVRAM_TYPE_UINT64_ARRAY:
152		return ("uint64[]");
153	case BHND_NVRAM_TYPE_INT8_ARRAY:
154		return ("int8[]");
155	case BHND_NVRAM_TYPE_INT16_ARRAY:
156		return ("int16[]");
157	case BHND_NVRAM_TYPE_INT32_ARRAY:
158		return ("int32[]");
159	case BHND_NVRAM_TYPE_INT64_ARRAY:
160		return ("int64[]");
161	case BHND_NVRAM_TYPE_CHAR_ARRAY:
162		return ("char[]");
163	case BHND_NVRAM_TYPE_STRING_ARRAY:
164		return ("string[]");
165	case BHND_NVRAM_TYPE_BOOL_ARRAY:
166		return ("bool[]");
167	}
168
169	/* Quiesce gcc4.2 */
170	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
171}
172
173/**
174 * Return true if @p type is a signed integer type, false otherwise.
175 *
176 * Will return false for all array types.
177 *
178 * @param type The type to query.
179 */
180bool
181bhnd_nvram_is_signed_type(bhnd_nvram_type type)
182{
183	switch (type) {
184	case BHND_NVRAM_TYPE_INT8:
185	case BHND_NVRAM_TYPE_INT16:
186	case BHND_NVRAM_TYPE_INT32:
187	case BHND_NVRAM_TYPE_INT64:
188		BHND_NV_ASSERT(bhnd_nvram_is_int_type(type), ("non-int type?"));
189		return (true);
190
191	case BHND_NVRAM_TYPE_CHAR:
192	case BHND_NVRAM_TYPE_UINT8:
193	case BHND_NVRAM_TYPE_UINT16:
194	case BHND_NVRAM_TYPE_UINT32:
195	case BHND_NVRAM_TYPE_UINT64:
196	case BHND_NVRAM_TYPE_STRING:
197	case BHND_NVRAM_TYPE_BOOL:
198	case BHND_NVRAM_TYPE_NULL:
199	case BHND_NVRAM_TYPE_DATA:
200	case BHND_NVRAM_TYPE_UINT8_ARRAY:
201	case BHND_NVRAM_TYPE_UINT16_ARRAY:
202	case BHND_NVRAM_TYPE_UINT32_ARRAY:
203	case BHND_NVRAM_TYPE_UINT64_ARRAY:
204	case BHND_NVRAM_TYPE_INT8_ARRAY:
205	case BHND_NVRAM_TYPE_INT16_ARRAY:
206	case BHND_NVRAM_TYPE_INT32_ARRAY:
207	case BHND_NVRAM_TYPE_INT64_ARRAY:
208	case BHND_NVRAM_TYPE_CHAR_ARRAY:
209	case BHND_NVRAM_TYPE_STRING_ARRAY:
210	case BHND_NVRAM_TYPE_BOOL_ARRAY:
211		return (false);
212	}
213
214	/* Quiesce gcc4.2 */
215	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
216}
217
218/**
219 * Return true if @p type is an unsigned integer type, false otherwise.
220 *
221 * @param type The type to query.
222 *
223 * @return Will return false for all array types.
224 * @return Will return true for BHND_NVRAM_TYPE_CHAR.
225 */
226bool
227bhnd_nvram_is_unsigned_type(bhnd_nvram_type type)
228{
229	/* If an integer type, must be either signed or unsigned */
230	if (!bhnd_nvram_is_int_type(type))
231		return (false);
232
233	return (!bhnd_nvram_is_signed_type(type));
234}
235
236/**
237 * Return true if bhnd_nvram_is_signed_type() or bhnd_nvram_is_unsigned_type()
238 * returns true for @p type.
239 *
240 * @param type The type to query.
241 */
242bool
243bhnd_nvram_is_int_type(bhnd_nvram_type type)
244{
245	switch (type) {
246	case BHND_NVRAM_TYPE_UINT8:
247	case BHND_NVRAM_TYPE_UINT16:
248	case BHND_NVRAM_TYPE_UINT32:
249	case BHND_NVRAM_TYPE_UINT64:
250	case BHND_NVRAM_TYPE_INT8:
251	case BHND_NVRAM_TYPE_INT16:
252	case BHND_NVRAM_TYPE_INT32:
253	case BHND_NVRAM_TYPE_INT64:
254		return (true);
255
256	case BHND_NVRAM_TYPE_CHAR:
257	case BHND_NVRAM_TYPE_STRING:
258	case BHND_NVRAM_TYPE_BOOL:
259	case BHND_NVRAM_TYPE_NULL:
260	case BHND_NVRAM_TYPE_DATA:
261	case BHND_NVRAM_TYPE_UINT8_ARRAY:
262	case BHND_NVRAM_TYPE_UINT16_ARRAY:
263	case BHND_NVRAM_TYPE_UINT32_ARRAY:
264	case BHND_NVRAM_TYPE_UINT64_ARRAY:
265	case BHND_NVRAM_TYPE_INT8_ARRAY:
266	case BHND_NVRAM_TYPE_INT16_ARRAY:
267	case BHND_NVRAM_TYPE_INT32_ARRAY:
268	case BHND_NVRAM_TYPE_INT64_ARRAY:
269	case BHND_NVRAM_TYPE_CHAR_ARRAY:
270	case BHND_NVRAM_TYPE_STRING_ARRAY:
271	case BHND_NVRAM_TYPE_BOOL_ARRAY:
272		return (false);
273	}
274
275	/* Quiesce gcc4.2 */
276	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
277}
278
279/**
280 * Return true if @p type is an array type, false otherwise.
281 *
282 * @param type The type to query.
283 */
284bool
285bhnd_nvram_is_array_type(bhnd_nvram_type type)
286{
287	switch (type) {
288	case BHND_NVRAM_TYPE_UINT8:
289	case BHND_NVRAM_TYPE_UINT16:
290	case BHND_NVRAM_TYPE_UINT32:
291	case BHND_NVRAM_TYPE_UINT64:
292	case BHND_NVRAM_TYPE_INT8:
293	case BHND_NVRAM_TYPE_INT16:
294	case BHND_NVRAM_TYPE_INT32:
295	case BHND_NVRAM_TYPE_INT64:
296	case BHND_NVRAM_TYPE_CHAR:
297	case BHND_NVRAM_TYPE_STRING:
298	case BHND_NVRAM_TYPE_BOOL:
299	case BHND_NVRAM_TYPE_NULL:
300	case BHND_NVRAM_TYPE_DATA:
301		return (false);
302
303	case BHND_NVRAM_TYPE_UINT8_ARRAY:
304	case BHND_NVRAM_TYPE_UINT16_ARRAY:
305	case BHND_NVRAM_TYPE_UINT32_ARRAY:
306	case BHND_NVRAM_TYPE_UINT64_ARRAY:
307	case BHND_NVRAM_TYPE_INT8_ARRAY:
308	case BHND_NVRAM_TYPE_INT16_ARRAY:
309	case BHND_NVRAM_TYPE_INT32_ARRAY:
310	case BHND_NVRAM_TYPE_INT64_ARRAY:
311	case BHND_NVRAM_TYPE_CHAR_ARRAY:
312	case BHND_NVRAM_TYPE_STRING_ARRAY:
313	case BHND_NVRAM_TYPE_BOOL_ARRAY:
314		return (true);
315	}
316
317	/* Quiesce gcc4.2 */
318	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
319}
320
321/**
322 * If @p type is an array type, return the base element type. Otherwise,
323 * returns @p type.
324 *
325 * @param type The type to query.
326 */
327bhnd_nvram_type
328bhnd_nvram_base_type(bhnd_nvram_type type)
329{
330	switch (type) {
331	case BHND_NVRAM_TYPE_UINT8:
332	case BHND_NVRAM_TYPE_UINT16:
333	case BHND_NVRAM_TYPE_UINT32:
334	case BHND_NVRAM_TYPE_UINT64:
335	case BHND_NVRAM_TYPE_INT8:
336	case BHND_NVRAM_TYPE_INT16:
337	case BHND_NVRAM_TYPE_INT32:
338	case BHND_NVRAM_TYPE_INT64:
339	case BHND_NVRAM_TYPE_CHAR:
340	case BHND_NVRAM_TYPE_STRING:
341	case BHND_NVRAM_TYPE_BOOL:
342	case BHND_NVRAM_TYPE_NULL:
343	case BHND_NVRAM_TYPE_DATA:
344		return (type);
345
346	case BHND_NVRAM_TYPE_UINT8_ARRAY:	return (BHND_NVRAM_TYPE_UINT8);
347	case BHND_NVRAM_TYPE_UINT16_ARRAY:	return (BHND_NVRAM_TYPE_UINT16);
348	case BHND_NVRAM_TYPE_UINT32_ARRAY:	return (BHND_NVRAM_TYPE_UINT32);
349	case BHND_NVRAM_TYPE_UINT64_ARRAY:	return (BHND_NVRAM_TYPE_UINT64);
350	case BHND_NVRAM_TYPE_INT8_ARRAY:	return (BHND_NVRAM_TYPE_INT8);
351	case BHND_NVRAM_TYPE_INT16_ARRAY:	return (BHND_NVRAM_TYPE_INT16);
352	case BHND_NVRAM_TYPE_INT32_ARRAY:	return (BHND_NVRAM_TYPE_INT32);
353	case BHND_NVRAM_TYPE_INT64_ARRAY:	return (BHND_NVRAM_TYPE_INT64);
354	case BHND_NVRAM_TYPE_CHAR_ARRAY:	return (BHND_NVRAM_TYPE_CHAR);
355	case BHND_NVRAM_TYPE_STRING_ARRAY:	return (BHND_NVRAM_TYPE_STRING);
356	case BHND_NVRAM_TYPE_BOOL_ARRAY:	return (BHND_NVRAM_TYPE_BOOL);
357	}
358
359	/* Quiesce gcc4.2 */
360	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
361}
362
363/**
364 * Return the raw data type used to represent values of @p type, or return
365 * @p type is @p type is not a complex type.
366 *
367 * @param type The type to query.
368 */
369bhnd_nvram_type
370bhnd_nvram_raw_type(bhnd_nvram_type type)
371{
372	switch (type) {
373	case BHND_NVRAM_TYPE_CHAR:
374		return (BHND_NVRAM_TYPE_UINT8);
375
376	case BHND_NVRAM_TYPE_CHAR_ARRAY:
377		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
378
379	case BHND_NVRAM_TYPE_BOOL: {
380		_Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
381		    "bhnd_nvram_bool_t must be uint8-representable");
382		return (BHND_NVRAM_TYPE_UINT8);
383	}
384
385	case BHND_NVRAM_TYPE_BOOL_ARRAY:
386		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
387
388	case BHND_NVRAM_TYPE_DATA:
389		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
390
391	case BHND_NVRAM_TYPE_STRING:
392	case BHND_NVRAM_TYPE_STRING_ARRAY:
393		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
394
395	case BHND_NVRAM_TYPE_UINT8:
396	case BHND_NVRAM_TYPE_UINT16:
397	case BHND_NVRAM_TYPE_UINT32:
398	case BHND_NVRAM_TYPE_UINT64:
399	case BHND_NVRAM_TYPE_INT8:
400	case BHND_NVRAM_TYPE_INT16:
401	case BHND_NVRAM_TYPE_INT32:
402	case BHND_NVRAM_TYPE_INT64:
403	case BHND_NVRAM_TYPE_NULL:
404	case BHND_NVRAM_TYPE_UINT8_ARRAY:
405	case BHND_NVRAM_TYPE_UINT16_ARRAY:
406	case BHND_NVRAM_TYPE_UINT32_ARRAY:
407	case BHND_NVRAM_TYPE_UINT64_ARRAY:
408	case BHND_NVRAM_TYPE_INT8_ARRAY:
409	case BHND_NVRAM_TYPE_INT16_ARRAY:
410	case BHND_NVRAM_TYPE_INT32_ARRAY:
411	case BHND_NVRAM_TYPE_INT64_ARRAY:
412		return (type);
413	}
414
415	/* Quiesce gcc4.2 */
416	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
417}
418
419/**
420 * Return the size, in bytes, of a single element of @p type, or 0
421 * if @p type is a variable-width type.
422 *
423 * @param type	The type to query.
424 */
425size_t
426bhnd_nvram_type_width(bhnd_nvram_type type)
427{
428	switch (type) {
429	case BHND_NVRAM_TYPE_STRING:
430	case BHND_NVRAM_TYPE_STRING_ARRAY:
431	case BHND_NVRAM_TYPE_DATA:
432		return (0);
433
434	case BHND_NVRAM_TYPE_NULL:
435		return (0);
436
437	case BHND_NVRAM_TYPE_BOOL:
438	case BHND_NVRAM_TYPE_BOOL_ARRAY:
439		return (sizeof(bhnd_nvram_bool_t));
440
441	case BHND_NVRAM_TYPE_CHAR:
442	case BHND_NVRAM_TYPE_CHAR_ARRAY:
443	case BHND_NVRAM_TYPE_UINT8:
444	case BHND_NVRAM_TYPE_UINT8_ARRAY:
445	case BHND_NVRAM_TYPE_INT8:
446	case BHND_NVRAM_TYPE_INT8_ARRAY:
447		return (sizeof(uint8_t));
448
449	case BHND_NVRAM_TYPE_UINT16:
450	case BHND_NVRAM_TYPE_UINT16_ARRAY:
451	case BHND_NVRAM_TYPE_INT16:
452	case BHND_NVRAM_TYPE_INT16_ARRAY:
453		return (sizeof(uint16_t));
454
455	case BHND_NVRAM_TYPE_UINT32:
456	case BHND_NVRAM_TYPE_UINT32_ARRAY:
457	case BHND_NVRAM_TYPE_INT32:
458	case BHND_NVRAM_TYPE_INT32_ARRAY:
459		return (sizeof(uint32_t));
460
461	case BHND_NVRAM_TYPE_UINT64:
462	case BHND_NVRAM_TYPE_UINT64_ARRAY:
463	case BHND_NVRAM_TYPE_INT64:
464	case BHND_NVRAM_TYPE_INT64_ARRAY:
465		return (sizeof(uint64_t));
466	}
467
468	/* Quiesce gcc4.2 */
469	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
470}
471
472/**
473 * Return the native host alignment for values of @p type.
474 *
475 * @param type The type to query.
476 */
477size_t
478bhnd_nvram_type_host_align(bhnd_nvram_type type)
479{
480	switch (type) {
481	case BHND_NVRAM_TYPE_CHAR:
482	case BHND_NVRAM_TYPE_CHAR_ARRAY:
483	case BHND_NVRAM_TYPE_DATA:
484	case BHND_NVRAM_TYPE_STRING:
485	case BHND_NVRAM_TYPE_STRING_ARRAY:
486		return (_Alignof(uint8_t));
487	case BHND_NVRAM_TYPE_BOOL:
488	case BHND_NVRAM_TYPE_BOOL_ARRAY: {
489		_Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
490		    "bhnd_nvram_bool_t must be uint8-representable");
491		return (_Alignof(uint8_t));
492	}
493	case BHND_NVRAM_TYPE_NULL:
494		return (1);
495	case BHND_NVRAM_TYPE_UINT8:
496	case BHND_NVRAM_TYPE_UINT8_ARRAY:
497		return (_Alignof(uint8_t));
498	case BHND_NVRAM_TYPE_UINT16:
499	case BHND_NVRAM_TYPE_UINT16_ARRAY:
500		return (_Alignof(uint16_t));
501	case BHND_NVRAM_TYPE_UINT32:
502	case BHND_NVRAM_TYPE_UINT32_ARRAY:
503		return (_Alignof(uint32_t));
504	case BHND_NVRAM_TYPE_UINT64:
505	case BHND_NVRAM_TYPE_UINT64_ARRAY:
506		return (_Alignof(uint64_t));
507	case BHND_NVRAM_TYPE_INT8:
508	case BHND_NVRAM_TYPE_INT8_ARRAY:
509		return (_Alignof(int8_t));
510	case BHND_NVRAM_TYPE_INT16:
511	case BHND_NVRAM_TYPE_INT16_ARRAY:
512		return (_Alignof(int16_t));
513	case BHND_NVRAM_TYPE_INT32:
514	case BHND_NVRAM_TYPE_INT32_ARRAY:
515		return (_Alignof(int32_t));
516	case BHND_NVRAM_TYPE_INT64:
517	case BHND_NVRAM_TYPE_INT64_ARRAY:
518		return (_Alignof(int64_t));
519	}
520
521	/* Quiesce gcc4.2 */
522	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
523}
524
525/**
526 * Iterate over all strings in the @p inp string array (see
527 * BHND_NVRAM_TYPE_STRING_ARRAY).
528 *
529 * @param		inp	The string array to be iterated. This must be a
530 *				buffer of one or more NUL-terminated strings.
531 * @param		ilen	The size, in bytes, of @p inp, including any
532 *				terminating NUL character(s).
533 * @param		prev	The pointer previously returned by
534 *				bhnd_nvram_string_array_next(), or NULL to begin
535 *				iteration.
536* @param[in,out]	olen	If @p prev is non-NULL, @p olen must be a
537 *				pointer to the length previously returned by
538 *				bhnd_nvram_string_array_next(). On success, will
539 *				be set to the next element's length, in bytes.
540 *
541 * @retval non-NULL	A reference to the next NUL-terminated string
542 * @retval NULL		If the end of the string array is reached.
543 *
544 * @see BHND_NVRAM_TYPE_STRING_ARRAY
545 */
546const char *
547bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev,
548    size_t *olen)
549{
550	return (bhnd_nvram_value_array_next(inp, ilen,
551	    BHND_NVRAM_TYPE_STRING_ARRAY, prev, olen));
552}
553
554/* used by bhnd_nvram_find_vardefn() */
555static int
556bhnd_nvram_find_vardefn_compare(const void *key, const void *rhs)
557{
558	const struct bhnd_nvram_vardefn *r = rhs;
559
560	return (strcmp((const char *)key, r->name));
561}
562
563/**
564 * Find and return the variable definition for @p varname, if any.
565 *
566 * @param varname variable name
567 *
568 * @retval bhnd_nvram_vardefn If a valid definition for @p varname is found.
569 * @retval NULL If no definition for @p varname is found.
570 */
571const struct bhnd_nvram_vardefn *
572bhnd_nvram_find_vardefn(const char *varname)
573{
574	return (bsearch(varname, bhnd_nvram_vardefns, bhnd_nvram_num_vardefns,
575	    sizeof(bhnd_nvram_vardefns[0]), bhnd_nvram_find_vardefn_compare));
576}
577
578/**
579 * Return the variable ID for a variable definition.
580 *
581 * @param defn Variable definition previously returned by
582 * bhnd_nvram_find_vardefn() or bhnd_nvram_get_vardefn().
583 */
584size_t
585bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn *defn)
586{
587	BHND_NV_ASSERT(
588	    defn >= bhnd_nvram_vardefns &&
589	    defn <= &bhnd_nvram_vardefns[bhnd_nvram_num_vardefns-1],
590	    ("invalid variable definition pointer %p", defn));
591
592	return (defn - bhnd_nvram_vardefns);
593}
594
595/**
596 * Return the variable definition with the given @p id, or NULL
597 * if no such variable ID is defined.
598 *
599 * @param id variable ID.
600 *
601 * @retval bhnd_nvram_vardefn If a valid definition for @p id is found.
602 * @retval NULL If no definition for @p id is found.
603 */
604const struct bhnd_nvram_vardefn *
605bhnd_nvram_get_vardefn(size_t id)
606{
607	if (id >= bhnd_nvram_num_vardefns)
608		return (NULL);
609
610	return (&bhnd_nvram_vardefns[id]);
611}
612
613/**
614 * Validate an NVRAM variable name.
615 *
616 * Scans for special characters (path delimiters, value delimiters, path
617 * alias prefixes), returning false if the given name cannot be used
618 * as a relative NVRAM key.
619 *
620 * @param name A relative NVRAM variable name to validate.
621 *
622 * @retval true If @p name is a valid relative NVRAM key.
623 * @retval false If @p name should not be used as a relative NVRAM key.
624 */
625bool
626bhnd_nvram_validate_name(const char *name)
627{
628	/* Reject path-prefixed variable names */
629	if (bhnd_nvram_trim_path_name(name) != name)
630		return (false);
631
632	/* Reject device path alias declarations (devpath[1-9][0-9]*.*\0) */
633	if (strncmp(name, "devpath", strlen("devpath")) == 0) {
634		const char	*p;
635		char		*endp;
636
637		/* Check for trailing [1-9][0-9]* */
638		p = name + strlen("devpath");
639		strtoul(p, &endp, 10);
640		if (endp != p)
641			return (false);
642	}
643
644	/* Scan for [^A-Za-z_0-9] */
645	for (const char *p = name; *p != '\0'; p++) {
646		switch (*p) {
647		/* [0-9_] */
648		case '0': case '1': case '2': case '3': case '4':
649		case '5': case '6': case '7': case '8': case '9':
650		case '_':
651			break;
652
653		/* [A-Za-z] */
654		default:
655			if (!bhnd_nv_isalpha(*p))
656				return (false);
657			break;
658		}
659	}
660
661	return (true);
662}
663
664/**
665 * Parses the string in the optionally NUL-terminated @p str to as an integer
666 * value of @p otype, accepting any integer format supported by the standard
667 * strtoul().
668 *
669 * - Any leading whitespace in @p str -- as defined by the equivalent of
670 *   calling isspace_l() with an ASCII locale -- will be ignored.
671 * - A @p str may be prefixed with a single optional '+' or '-' sign denoting
672 *   signedness.
673 * - A hexadecimal @p str may include an '0x' or '0X' prefix, denoting that a
674 *   base 16 integer follows.
675 * - An octal @p str may include a '0' prefix, denoting that an octal integer
676 *   follows.
677 *
678 * If a @p base of 0 is specified, the base will be determined according
679 * to the string's initial prefix, as per strtoul()'s documented behavior.
680 *
681 * When parsing a base 16 integer to a signed representation, if no explicit
682 * sign prefix is given, the string will be parsed as the raw two's complement
683 * representation of the signed integer value.
684 *
685 * @param		str	The string to be parsed.
686 * @param		maxlen	The maximum number of bytes to be read in
687 *				@p str.
688 * @param		base	The input string's base (2-36), or 0.
689 * @param[out]		nbytes	On success or failure, will be set to the total
690 *				number of parsed bytes. If the total number of
691 *				bytes is not desired, a NULL pointer may be
692 *				provided.
693 * @param[out]		outp	On success, the parsed integer value will be
694 *				written to @p outp. This argment may be NULL if
695 *				the value is not desired.
696 * @param[in,out]	olen	The capacity of @p outp. On success, will be set
697 *				to the actual size of the requested value.
698 * @param		otype	The integer type to be parsed.
699 *
700 * @retval 0		success
701 * @retval EINVAL	if an invalid @p base is specified.
702 * @retval EINVAL	if an unsupported (or non-integer) @p otype is
703 *			specified.
704 * @retval ENOMEM	If @p outp is non-NULL and a buffer of @p olen is too
705 *			small to hold the requested value.
706 * @retval EFTYPE	if @p str cannot be parsed as an integer of @p base.
707 * @retval ERANGE	If the integer parsed from @p str is too large to be
708 *			represented as a value of @p otype.
709 */
710int
711bhnd_nvram_parse_int(const char *str, size_t maxlen,  u_int base,
712    size_t *nbytes, void *outp, size_t *olen, bhnd_nvram_type otype)
713{
714	uint64_t	value;
715	uint64_t	carry_max, value_max;
716	uint64_t	type_max;
717	size_t		limit, local_nbytes;
718	size_t		ndigits;
719	bool		negative, sign, twos_compl;
720
721	/* Must be an integer type */
722	if (!bhnd_nvram_is_int_type(otype))
723		return (EINVAL);
724
725	/* Determine output byte limit */
726	if (outp != NULL)
727		limit = *olen;
728	else
729		limit = 0;
730
731	/* We always need a byte count. If the caller provides a NULL nbytes,
732	 * track our position in a stack variable */
733	if (nbytes == NULL)
734		nbytes = &local_nbytes;
735
736	value = 0;
737	ndigits = 0;
738	*nbytes = 0;
739	negative = false;
740	sign = false;
741
742	/* Validate the specified base */
743	if (base != 0 && !(base >= 2 && base <= 36))
744		return (EINVAL);
745
746	/* Skip any leading whitespace */
747	for (; *nbytes < maxlen; (*nbytes)++) {
748		if (!bhnd_nv_isspace(str[*nbytes]))
749			break;
750	}
751
752	/* Empty string? */
753	if (*nbytes == maxlen)
754		return (EFTYPE);
755
756	/* Parse and skip sign */
757	if (str[*nbytes] == '-') {
758		negative = true;
759		sign = true;
760		(*nbytes)++;
761	} else if (str[*nbytes] == '+') {
762		sign = true;
763		(*nbytes)++;
764	}
765
766	/* Truncated after sign character? */
767	if (*nbytes == maxlen)
768		return (EFTYPE);
769
770	/* Identify (or validate) hex base, skipping 0x/0X prefix */
771	if (base == 16 || base == 0) {
772		/* Check for (and skip) 0x/0X prefix */
773		if (maxlen - *nbytes >= 2 && str[*nbytes] == '0' &&
774		    (str[*nbytes+1] == 'x' || str[*nbytes+1] == 'X'))
775		{
776			base = 16;
777			(*nbytes) += 2;
778		}
779	}
780
781	/* Truncated after hex prefix? */
782	if (*nbytes == maxlen)
783		return (EFTYPE);
784
785	/* Differentiate decimal/octal by looking for a leading 0 */
786	if (base == 0) {
787		if (str[*nbytes] == '0') {
788			base = 8;
789		} else {
790			base = 10;
791		}
792	}
793
794	/* Only enable twos-compliment signed integer parsing enabled if the
795	 * input is base 16, and no explicit sign prefix was provided */
796	if (!sign && base == 16)
797		twos_compl = true;
798	else
799		twos_compl = false;
800
801	/* Determine the maximum value representable by the requested type */
802	switch (otype) {
803	case BHND_NVRAM_TYPE_CHAR:
804	case BHND_NVRAM_TYPE_UINT8:
805		type_max = (uint64_t)UINT8_MAX;
806		break;
807	case BHND_NVRAM_TYPE_UINT16:
808		type_max = (uint64_t)UINT16_MAX;
809		break;
810	case BHND_NVRAM_TYPE_UINT32:
811		type_max = (uint64_t)UINT32_MAX;
812		break;
813	case BHND_NVRAM_TYPE_UINT64:
814		type_max = (uint64_t)UINT64_MAX;
815		break;
816
817	case BHND_NVRAM_TYPE_INT8:
818		if (twos_compl)
819			type_max = (uint64_t)UINT8_MAX;
820		else if (negative)
821			type_max = -(uint64_t)INT8_MIN;
822		else
823			type_max = (uint64_t)INT8_MAX;
824		break;
825
826	case BHND_NVRAM_TYPE_INT16:
827		if (twos_compl)
828			type_max = (uint64_t)UINT16_MAX;
829		else if (negative)
830			type_max = -(uint64_t)INT16_MIN;
831		else
832			type_max = (uint64_t)INT16_MAX;
833		break;
834
835	case BHND_NVRAM_TYPE_INT32:
836		if (twos_compl)
837			type_max = (uint64_t)UINT32_MAX;
838		else if (negative)
839			type_max = -(uint64_t)INT32_MIN;
840		else
841			type_max = (uint64_t)INT32_MAX;
842		break;
843
844	case BHND_NVRAM_TYPE_INT64:
845		if (twos_compl)
846			type_max = (uint64_t)UINT64_MAX;
847		else if (negative)
848			type_max = -(uint64_t)INT64_MIN;
849		else
850			type_max = (uint64_t)INT64_MAX;
851		break;
852
853	default:
854		BHND_NV_LOG("unsupported integer type: %d\n", otype);
855		return (EINVAL);
856	}
857
858	/* The maximum value after which an additional carry would overflow */
859	value_max = type_max / (uint64_t)base;
860
861	/* The maximum carry value given a value equal to value_max */
862	carry_max = type_max % (uint64_t)base;
863
864	/* Consume input until we hit maxlen or a non-digit character */
865	for (; *nbytes < maxlen; (*nbytes)++) {
866		u_long	carry;
867		char	c;
868
869		/* Parse carry value */
870		c = str[*nbytes];
871		if (bhnd_nv_isdigit(c)) {
872			carry = c - '0';
873		} else if (bhnd_nv_isxdigit(c)) {
874			if (bhnd_nv_isupper(c))
875				carry = (c - 'A') + 10;
876			else
877				carry = (c - 'a') + 10;
878		} else {
879			/* Hit first non-digit character */
880			break;
881		}
882
883		/* If carry is outside the base, it's not a valid digit
884		 * in the current parse context; consider it a non-digit
885		 * character */
886		if (carry >= (uint64_t)base)
887			break;
888
889		/* Increment count of parsed digits */
890		ndigits++;
891
892		if (value > value_max) {
893			/* -Any- carry value would overflow */
894			return (ERANGE);
895		} else if (value == value_max && carry > carry_max) {
896			/* -This- carry value would overflow */
897			return (ERANGE);
898		}
899
900		value *= (uint64_t)base;
901		value += carry;
902	}
903
904	/* If we hit a non-digit character before parsing the first digit,
905	 * we hit an empty integer string. */
906	if (ndigits == 0)
907		return (EFTYPE);
908
909	if (negative)
910		value = -value;
911
912	/* Provide (and verify) required length */
913	*olen = bhnd_nvram_type_width(otype);
914	if (outp == NULL)
915		return (0);
916	else if (limit < *olen)
917		return (ENOMEM);
918
919	/* Provide result */
920	switch (otype) {
921	case BHND_NVRAM_TYPE_CHAR:
922	case BHND_NVRAM_TYPE_UINT8:
923		*(uint8_t *)outp = (uint8_t)value;
924		break;
925	case BHND_NVRAM_TYPE_UINT16:
926		*(uint16_t *)outp = (uint16_t)value;
927		break;
928	case BHND_NVRAM_TYPE_UINT32:
929		*(uint32_t *)outp = (uint32_t)value;
930		break;
931	case BHND_NVRAM_TYPE_UINT64:
932		*(uint64_t *)outp = (uint64_t)value;
933		break;
934
935	case BHND_NVRAM_TYPE_INT8:
936		*(int8_t *)outp = (int8_t)(int64_t)value;
937		break;
938	case BHND_NVRAM_TYPE_INT16:
939		*(int16_t *)outp = (int16_t)(int64_t)value;
940		break;
941	case BHND_NVRAM_TYPE_INT32:
942		*(int32_t *)outp = (int32_t)(int64_t)value;
943		break;
944	case BHND_NVRAM_TYPE_INT64:
945		*(int64_t *)outp = (int64_t)value;
946		break;
947	default:
948		/* unreachable */
949		BHND_NV_PANIC("unhandled type %d\n", otype);
950	}
951
952	return (0);
953}
954
955/**
956 * Trim leading path (pci/1/1) or path alias (0:) prefix from @p name, if any,
957 * returning a pointer to the start of the relative variable name.
958 *
959 * @par Examples
960 *
961 * - "/foo"		-> "foo"
962 * - "dev/pci/foo"	-> "foo"
963 * - "0:foo"		-> "foo"
964 * - "foo"		-> "foo"
965 *
966 * @param name The string to be trimmed.
967 *
968 * @return A pointer to the start of the relative variable name in @p name.
969 */
970const char *
971bhnd_nvram_trim_path_name(const char *name)
972{
973	char *endp;
974
975	/* path alias prefix? (0:varname) */
976	if (bhnd_nv_isdigit(*name)) {
977		/* Parse '0...:' alias prefix, if it exists */
978		strtoul(name, &endp, 10);
979		if (endp != name && *endp == ':') {
980			/* Variable name follows 0: prefix */
981			return (endp+1);
982		}
983	}
984
985	/* device path prefix? (pci/1/1/varname) */
986	if ((endp = strrchr(name, '/')) != NULL) {
987		/* Variable name follows the final path separator '/' */
988		return (endp+1);
989	}
990
991	/* variable name is not prefixed */
992	return (name);
993}
994
995/**
996 * Parse a 'name=value' string.
997 *
998 * @param env The string to be parsed.
999 * @param env_len The length of @p envp.
1000 * @param delim The delimiter used in @p envp. This will generally be '='.
1001 * @param[out] name If not NULL, a pointer to the name string. This argument
1002 * may be NULL.
1003 * @param[out] name_len On success, the length of the name substring. This
1004 * argument may be NULL.
1005 * @param[out] value On success, a pointer to the value substring. This argument
1006 * may be NULL.
1007 * @param[out] value_len On success, the length of the value substring. This
1008 * argument may be NULL.
1009 *
1010 * @retval 0 success
1011 * @retval EINVAL if parsing @p envp fails.
1012 */
1013int
1014bhnd_nvram_parse_env(const char *env, size_t env_len, char delim,
1015    const char **name, size_t *name_len, const char **value, size_t *value_len)
1016{
1017	const char *p;
1018
1019	/* Name */
1020	if ((p = memchr(env, delim, env_len)) == NULL) {
1021		BHND_NV_LOG("delimiter '%c' not found in '%.*s'\n", delim,
1022		    BHND_NV_PRINT_WIDTH(env_len), env);
1023		return (EINVAL);
1024	}
1025
1026	/* Name */
1027	if (name != NULL)
1028		*name = env;
1029	if (name_len != NULL)
1030		*name_len = p - env;
1031
1032	/* Skip delim */
1033	p++;
1034
1035	/* Value */
1036	if (value != NULL)
1037		*value = p;
1038	if (value_len != NULL)
1039		*value_len = env_len - (p - env);
1040
1041	return (0);
1042}
1043
1044/**
1045 * Parse a field value, returning the actual pointer to the first
1046 * non-whitespace character and the total size of the field.
1047 *
1048 * @param[in,out] inp The field string to parse. Will be updated to point
1049 * at the first non-whitespace character found.
1050 * @param ilen The length of @p inp, in bytes.
1051 * @param delim The field delimiter to search for.
1052 *
1053 * @return Returns the actual size of the field data.
1054 */
1055size_t
1056bhnd_nvram_parse_field(const char **inp, size_t ilen, char delim)
1057{
1058	const char	*p, *sp;
1059
1060	/* Skip any leading whitespace */
1061	for (sp = *inp; (size_t)(sp-*inp) < ilen && bhnd_nv_isspace(*sp); sp++)
1062		continue;
1063
1064	*inp = sp;
1065
1066	/* Find the last field character */
1067	for (p = *inp; (size_t)(p - *inp) < ilen; p++) {
1068		if (*p == delim || *p == '\0')
1069			break;
1070	}
1071
1072	return (p - *inp);
1073}
1074
1075/**
1076 * Parse a field value, returning the actual pointer to the first
1077 * non-whitespace character and the total size of the field, minus
1078 * any trailing whitespace.
1079 *
1080 * @param[in,out] inp The field string to parse. Will be updated to point
1081 * at the first non-whitespace character found.
1082 * @param ilen The length of the parsed field, in bytes, excluding the
1083 * field elimiter and any trailing whitespace.
1084 * @param delim The field delimiter to search for.
1085 *
1086 * @return Returns the actual size of the field data.
1087 */
1088size_t
1089bhnd_nvram_trim_field(const char **inp, size_t ilen, char delim)
1090{
1091	const char	*sp;
1092	size_t		 plen;
1093
1094	plen = bhnd_nvram_parse_field(inp, ilen, delim);
1095
1096	/* Trim trailing whitespace */
1097	sp = *inp;
1098	while (plen > 0) {
1099		if (!bhnd_nv_isspace(*(sp + plen - 1)))
1100			break;
1101
1102		plen--;
1103	}
1104
1105	return (plen);
1106}
1107