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 *
bhnd_nvram_type_name(bhnd_nvram_type type)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
bhnd_nvram_is_signed_type(bhnd_nvram_type type)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
bhnd_nvram_is_unsigned_type(bhnd_nvram_type type)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
bhnd_nvram_is_int_type(bhnd_nvram_type type)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
bhnd_nvram_is_array_type(bhnd_nvram_type type)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
bhnd_nvram_base_type(bhnd_nvram_type 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
bhnd_nvram_raw_type(bhnd_nvram_type 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
bhnd_nvram_type_width(bhnd_nvram_type type)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
bhnd_nvram_type_host_align(bhnd_nvram_type type)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 *
bhnd_nvram_string_array_next(const char * inp,size_t ilen,const char * prev,size_t * olen)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
bhnd_nvram_find_vardefn_compare(const void * key,const void * rhs)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 *
bhnd_nvram_find_vardefn(const char * varname)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
bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn * defn)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 *
bhnd_nvram_get_vardefn(size_t id)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
bhnd_nvram_validate_name(const char * name)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
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)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 *
bhnd_nvram_trim_path_name(const char * name)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
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)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
bhnd_nvram_parse_field(const char ** inp,size_t ilen,char delim)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
bhnd_nvram_trim_field(const char ** inp,size_t ilen,char delim)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