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 *
bhnd_nvram_type_name(bhnd_nvram_type type)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
bhnd_nvram_is_signed_type(bhnd_nvram_type type)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
bhnd_nvram_is_unsigned_type(bhnd_nvram_type type)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
bhnd_nvram_is_int_type(bhnd_nvram_type type)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
bhnd_nvram_is_array_type(bhnd_nvram_type type)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
bhnd_nvram_base_type(bhnd_nvram_type 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
bhnd_nvram_raw_type(bhnd_nvram_type 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
bhnd_nvram_type_width(bhnd_nvram_type type)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
bhnd_nvram_type_host_align(bhnd_nvram_type type)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 *
bhnd_nvram_string_array_next(const char * inp,size_t ilen,const char * prev,size_t * olen)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
bhnd_nvram_find_vardefn_compare(const void * key,const void * rhs)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 *
bhnd_nvram_find_vardefn(const char * varname)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
bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn * defn)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 *
bhnd_nvram_get_vardefn(size_t id)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
bhnd_nvram_validate_name(const char * name)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
bhnd_nvram_parse_int(const char * str,size_t maxlen,u_int base,size_t * nbytes,void * outp,size_t * olen,bhnd_nvram_type otype)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 *
bhnd_nvram_trim_path_name(const char * name)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
bhnd_nvram_parse_env(const char * env,size_t env_len,char delim,const char ** name,size_t * name_len,const char ** value,size_t * value_len)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
bhnd_nvram_parse_field(const char ** inp,size_t ilen,char delim)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
bhnd_nvram_trim_field(const char ** inp,size_t ilen,char delim)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