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