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