]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/nvram/bhnd_nvram_subr.c
Pull down pjdfstest 0.1
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / nvram / bhnd_nvram_subr.c
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34
35 #ifdef _KERNEL
36
37 #include <sys/ctype.h>
38 #include <sys/kernel.h>
39 #include <sys/limits.h>
40 #include <sys/malloc.h>
41 #include <sys/systm.h>
42
43 #include <machine/_inttypes.h>
44
45 #else /* !_KERNEL */
46
47 #include <ctype.h>
48 #include <errno.h>
49 #include <inttypes.h>
50 #include <limits.h>
51 #include <stdbool.h>
52 #include <stdio.h>
53 #include <stdint.h>
54 #include <stdlib.h>
55 #include <string.h>
56
57 #endif /* _KERNEL */
58
59 #include "bhnd_nvram_io.h"
60 #include "bhnd_nvram_private.h"
61 #include "bhnd_nvram_value.h"
62
63 #include "bhnd_nvram_map_data.h"
64
65 /*
66  * Common NVRAM/SPROM support, including NVRAM variable map
67  * lookup.
68  */
69
70 #ifdef _KERNEL
71 MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data");
72 #endif
73
74 /*
75  * CRC-8 lookup table used to checksum SPROM and NVRAM data via
76  * bhnd_nvram_crc8().
77  * 
78  * Generated with following parameters:
79  *      polynomial:     CRC-8 (x^8 + x^7 + x^6 + x^4 + x^2 + 1)
80  *      reflected bits: false
81  *      reversed:       true
82  */
83 const uint8_t bhnd_nvram_crc8_tab[] = {
84         0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b, 0x4a, 0xbd, 0xf3,
85         0x04, 0x6f, 0x98, 0xd6, 0x21, 0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46,
86         0x08, 0xff, 0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5, 0x7f,
87         0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14, 0x35, 0xc2, 0x8c, 0x7b,
88         0x10, 0xe7, 0xa9, 0x5e, 0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77,
89         0x80, 0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca, 0xfe, 0x09,
90         0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95, 0xb4, 0x43, 0x0d, 0xfa, 0x91,
91         0x66, 0x28, 0xdf, 0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01,
92         0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b, 0x81, 0x76, 0x38,
93         0xcf, 0xa4, 0x53, 0x1d, 0xea, 0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19,
94         0x57, 0xa0, 0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e, 0x5f,
95         0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34, 0xab, 0x5c, 0x12, 0xe5,
96         0x8e, 0x79, 0x37, 0xc0, 0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d,
97         0x8a, 0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54, 0x75, 0x82,
98         0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e, 0xd4, 0x23, 0x6d, 0x9a, 0xf1,
99         0x06, 0x48, 0xbf, 0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5,
100         0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b, 0x0a, 0xfd, 0xb3,
101         0x44, 0x2f, 0xd8, 0x96, 0x61, 0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87,
102         0xc9, 0x3e, 0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74, 0xc1,
103         0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa, 0x8b, 0x7c, 0x32, 0xc5,
104         0xae, 0x59, 0x17, 0xe0, 0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6,
105         0x41, 0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b, 0xbe, 0x49,
106         0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5, 0xf4, 0x03, 0x4d, 0xba, 0xd1,
107         0x26, 0x68, 0x9f
108 };
109
110 /**
111  * Return a human readable name for @p type.
112  * 
113  * @param type The type to query.
114  */
115 const char *
116 bhnd_nvram_type_name(bhnd_nvram_type type)
117 {
118         switch (type) {
119         case BHND_NVRAM_TYPE_UINT8:
120                 return ("uint8");
121         case BHND_NVRAM_TYPE_UINT16:
122                 return ("uint16");
123         case BHND_NVRAM_TYPE_UINT32:
124                 return ("uint32");
125         case BHND_NVRAM_TYPE_UINT64:
126                 return ("uint64");
127         case BHND_NVRAM_TYPE_CHAR:
128                 return ("char");
129         case BHND_NVRAM_TYPE_INT8:
130                 return ("int8");
131         case BHND_NVRAM_TYPE_INT16:
132                 return ("int16");
133         case BHND_NVRAM_TYPE_INT32:
134                 return ("int32");
135         case BHND_NVRAM_TYPE_INT64:
136                 return ("int64");
137         case BHND_NVRAM_TYPE_STRING:
138                 return ("string");
139         case BHND_NVRAM_TYPE_BOOL:
140                 return ("bool");
141         case BHND_NVRAM_TYPE_NULL:
142                 return ("null");
143         case BHND_NVRAM_TYPE_DATA:
144                 return ("data");
145         case BHND_NVRAM_TYPE_UINT8_ARRAY:
146                 return ("uint8[]");
147         case BHND_NVRAM_TYPE_UINT16_ARRAY:
148                 return ("uint16[]");
149         case BHND_NVRAM_TYPE_UINT32_ARRAY:
150                 return ("uint32[]");
151         case BHND_NVRAM_TYPE_UINT64_ARRAY:
152                 return ("uint64[]");
153         case BHND_NVRAM_TYPE_INT8_ARRAY:
154                 return ("int8[]");
155         case BHND_NVRAM_TYPE_INT16_ARRAY:
156                 return ("int16[]");
157         case BHND_NVRAM_TYPE_INT32_ARRAY:
158                 return ("int32[]");
159         case BHND_NVRAM_TYPE_INT64_ARRAY:
160                 return ("int64[]");
161         case BHND_NVRAM_TYPE_CHAR_ARRAY:
162                 return ("char[]");
163         case BHND_NVRAM_TYPE_STRING_ARRAY:
164                 return ("string[]");
165         case BHND_NVRAM_TYPE_BOOL_ARRAY:
166                 return ("bool[]");
167         }
168
169         /* Quiesce gcc4.2 */
170         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
171 }
172
173 /**
174  * Return true if @p type is a signed integer type, false otherwise.
175  * 
176  * Will return false for all array types.
177  * 
178  * @param type The type to query.
179  */
180 bool
181 bhnd_nvram_is_signed_type(bhnd_nvram_type type)
182 {
183         switch (type) {
184         case BHND_NVRAM_TYPE_INT8:
185         case BHND_NVRAM_TYPE_INT16:
186         case BHND_NVRAM_TYPE_INT32:
187         case BHND_NVRAM_TYPE_INT64:
188                 BHND_NV_ASSERT(bhnd_nvram_is_int_type(type), ("non-int type?"));
189                 return (true);
190
191         case BHND_NVRAM_TYPE_CHAR:
192         case BHND_NVRAM_TYPE_UINT8:
193         case BHND_NVRAM_TYPE_UINT16:
194         case BHND_NVRAM_TYPE_UINT32:
195         case BHND_NVRAM_TYPE_UINT64:
196         case BHND_NVRAM_TYPE_STRING:
197         case BHND_NVRAM_TYPE_BOOL:
198         case BHND_NVRAM_TYPE_NULL:
199         case BHND_NVRAM_TYPE_DATA:
200         case BHND_NVRAM_TYPE_UINT8_ARRAY:
201         case BHND_NVRAM_TYPE_UINT16_ARRAY:
202         case BHND_NVRAM_TYPE_UINT32_ARRAY:
203         case BHND_NVRAM_TYPE_UINT64_ARRAY:
204         case BHND_NVRAM_TYPE_INT8_ARRAY:
205         case BHND_NVRAM_TYPE_INT16_ARRAY:
206         case BHND_NVRAM_TYPE_INT32_ARRAY:
207         case BHND_NVRAM_TYPE_INT64_ARRAY:
208         case BHND_NVRAM_TYPE_CHAR_ARRAY:
209         case BHND_NVRAM_TYPE_STRING_ARRAY:
210         case BHND_NVRAM_TYPE_BOOL_ARRAY:
211                 return (false);
212         }
213
214         /* Quiesce gcc4.2 */
215         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
216 }
217
218 /**
219  * Return true if @p type is an unsigned integer type, false otherwise.
220  * 
221  * @param type The type to query.
222  *
223  * @return Will return false for all array types.
224  * @return Will return true for BHND_NVRAM_TYPE_CHAR.
225  */
226 bool
227 bhnd_nvram_is_unsigned_type(bhnd_nvram_type type)
228 {
229         /* If an integer type, must be either signed or unsigned */
230         if (!bhnd_nvram_is_int_type(type))
231                 return (false);
232
233         return (!bhnd_nvram_is_signed_type(type));
234 }
235
236 /**
237  * Return true if bhnd_nvram_is_signed_type() or bhnd_nvram_is_unsigned_type()
238  * returns true for @p type.
239  * 
240  * @param type The type to query.
241  */
242 bool
243 bhnd_nvram_is_int_type(bhnd_nvram_type type)
244 {
245         switch (type) {
246         case BHND_NVRAM_TYPE_UINT8:
247         case BHND_NVRAM_TYPE_UINT16:
248         case BHND_NVRAM_TYPE_UINT32:
249         case BHND_NVRAM_TYPE_UINT64:
250         case BHND_NVRAM_TYPE_INT8:
251         case BHND_NVRAM_TYPE_INT16:
252         case BHND_NVRAM_TYPE_INT32:
253         case BHND_NVRAM_TYPE_INT64:
254                 return (true);
255
256         case BHND_NVRAM_TYPE_CHAR:
257         case BHND_NVRAM_TYPE_STRING:
258         case BHND_NVRAM_TYPE_BOOL:
259         case BHND_NVRAM_TYPE_NULL:
260         case BHND_NVRAM_TYPE_DATA:
261         case BHND_NVRAM_TYPE_UINT8_ARRAY:
262         case BHND_NVRAM_TYPE_UINT16_ARRAY:
263         case BHND_NVRAM_TYPE_UINT32_ARRAY:
264         case BHND_NVRAM_TYPE_UINT64_ARRAY:
265         case BHND_NVRAM_TYPE_INT8_ARRAY:
266         case BHND_NVRAM_TYPE_INT16_ARRAY:
267         case BHND_NVRAM_TYPE_INT32_ARRAY:
268         case BHND_NVRAM_TYPE_INT64_ARRAY:
269         case BHND_NVRAM_TYPE_CHAR_ARRAY:
270         case BHND_NVRAM_TYPE_STRING_ARRAY:
271         case BHND_NVRAM_TYPE_BOOL_ARRAY:
272                 return (false);
273         }
274
275         /* Quiesce gcc4.2 */
276         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
277 }
278
279 /**
280  * Return true if @p type is an array type, false otherwise.
281  * 
282  * @param type The type to query.
283  */
284 bool
285 bhnd_nvram_is_array_type(bhnd_nvram_type type)
286 {
287         switch (type) {
288         case BHND_NVRAM_TYPE_UINT8:
289         case BHND_NVRAM_TYPE_UINT16:
290         case BHND_NVRAM_TYPE_UINT32:
291         case BHND_NVRAM_TYPE_UINT64:
292         case BHND_NVRAM_TYPE_INT8:
293         case BHND_NVRAM_TYPE_INT16:
294         case BHND_NVRAM_TYPE_INT32:
295         case BHND_NVRAM_TYPE_INT64:
296         case BHND_NVRAM_TYPE_CHAR:
297         case BHND_NVRAM_TYPE_STRING:
298         case BHND_NVRAM_TYPE_BOOL:
299         case BHND_NVRAM_TYPE_NULL:
300         case BHND_NVRAM_TYPE_DATA:
301                 return (false);
302
303         case BHND_NVRAM_TYPE_UINT8_ARRAY:
304         case BHND_NVRAM_TYPE_UINT16_ARRAY:
305         case BHND_NVRAM_TYPE_UINT32_ARRAY:
306         case BHND_NVRAM_TYPE_UINT64_ARRAY:
307         case BHND_NVRAM_TYPE_INT8_ARRAY:
308         case BHND_NVRAM_TYPE_INT16_ARRAY:
309         case BHND_NVRAM_TYPE_INT32_ARRAY:
310         case BHND_NVRAM_TYPE_INT64_ARRAY:
311         case BHND_NVRAM_TYPE_CHAR_ARRAY:
312         case BHND_NVRAM_TYPE_STRING_ARRAY:
313         case BHND_NVRAM_TYPE_BOOL_ARRAY:
314                 return (true);
315         }
316
317         /* Quiesce gcc4.2 */
318         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
319 }
320
321 /**
322  * If @p type is an array type, return the base element type. Otherwise,
323  * returns @p type.
324  * 
325  * @param type The type to query.
326  */
327 bhnd_nvram_type
328 bhnd_nvram_base_type(bhnd_nvram_type type)
329 {
330         switch (type) {
331         case BHND_NVRAM_TYPE_UINT8:
332         case BHND_NVRAM_TYPE_UINT16:
333         case BHND_NVRAM_TYPE_UINT32:
334         case BHND_NVRAM_TYPE_UINT64:
335         case BHND_NVRAM_TYPE_INT8:
336         case BHND_NVRAM_TYPE_INT16:
337         case BHND_NVRAM_TYPE_INT32:
338         case BHND_NVRAM_TYPE_INT64:
339         case BHND_NVRAM_TYPE_CHAR:
340         case BHND_NVRAM_TYPE_STRING:
341         case BHND_NVRAM_TYPE_BOOL:
342         case BHND_NVRAM_TYPE_NULL:
343         case BHND_NVRAM_TYPE_DATA:
344                 return (type);
345
346         case BHND_NVRAM_TYPE_UINT8_ARRAY:       return (BHND_NVRAM_TYPE_UINT8);
347         case BHND_NVRAM_TYPE_UINT16_ARRAY:      return (BHND_NVRAM_TYPE_UINT16);
348         case BHND_NVRAM_TYPE_UINT32_ARRAY:      return (BHND_NVRAM_TYPE_UINT32);
349         case BHND_NVRAM_TYPE_UINT64_ARRAY:      return (BHND_NVRAM_TYPE_UINT64);
350         case BHND_NVRAM_TYPE_INT8_ARRAY:        return (BHND_NVRAM_TYPE_INT8);
351         case BHND_NVRAM_TYPE_INT16_ARRAY:       return (BHND_NVRAM_TYPE_INT16);
352         case BHND_NVRAM_TYPE_INT32_ARRAY:       return (BHND_NVRAM_TYPE_INT32);
353         case BHND_NVRAM_TYPE_INT64_ARRAY:       return (BHND_NVRAM_TYPE_INT64);
354         case BHND_NVRAM_TYPE_CHAR_ARRAY:        return (BHND_NVRAM_TYPE_CHAR);
355         case BHND_NVRAM_TYPE_STRING_ARRAY:      return (BHND_NVRAM_TYPE_STRING);
356         case BHND_NVRAM_TYPE_BOOL_ARRAY:        return (BHND_NVRAM_TYPE_BOOL);
357         }
358
359         /* Quiesce gcc4.2 */
360         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
361 }
362
363 /**
364  * Return the raw data type used to represent values of @p type, or return
365  * @p type is @p type is not a complex type.
366  *
367  * @param type The type to query.
368  */
369 bhnd_nvram_type
370 bhnd_nvram_raw_type(bhnd_nvram_type type)
371 {
372         switch (type) {
373         case BHND_NVRAM_TYPE_CHAR:
374                 return (BHND_NVRAM_TYPE_UINT8);
375
376         case BHND_NVRAM_TYPE_CHAR_ARRAY:
377                 return (BHND_NVRAM_TYPE_UINT8_ARRAY);
378
379         case BHND_NVRAM_TYPE_BOOL: {
380                 _Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
381                     "bhnd_nvram_bool_t must be uint8-representable");
382                 return (BHND_NVRAM_TYPE_UINT8);
383         }
384
385         case BHND_NVRAM_TYPE_BOOL_ARRAY:
386                 return (BHND_NVRAM_TYPE_UINT8_ARRAY);
387
388         case BHND_NVRAM_TYPE_DATA:
389                 return (BHND_NVRAM_TYPE_UINT8_ARRAY);
390
391         case BHND_NVRAM_TYPE_STRING:
392         case BHND_NVRAM_TYPE_STRING_ARRAY:
393                 return (BHND_NVRAM_TYPE_UINT8_ARRAY);
394
395         case BHND_NVRAM_TYPE_UINT8:
396         case BHND_NVRAM_TYPE_UINT16:
397         case BHND_NVRAM_TYPE_UINT32:
398         case BHND_NVRAM_TYPE_UINT64:
399         case BHND_NVRAM_TYPE_INT8:
400         case BHND_NVRAM_TYPE_INT16:
401         case BHND_NVRAM_TYPE_INT32:
402         case BHND_NVRAM_TYPE_INT64:
403         case BHND_NVRAM_TYPE_NULL:
404         case BHND_NVRAM_TYPE_UINT8_ARRAY:
405         case BHND_NVRAM_TYPE_UINT16_ARRAY:
406         case BHND_NVRAM_TYPE_UINT32_ARRAY:
407         case BHND_NVRAM_TYPE_UINT64_ARRAY:
408         case BHND_NVRAM_TYPE_INT8_ARRAY:
409         case BHND_NVRAM_TYPE_INT16_ARRAY:
410         case BHND_NVRAM_TYPE_INT32_ARRAY:
411         case BHND_NVRAM_TYPE_INT64_ARRAY:
412                 return (type);
413         }
414
415         /* Quiesce gcc4.2 */
416         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
417 }
418
419 /**
420  * Return the size, in bytes, of a single element of @p type, or 0
421  * if @p type is a variable-width type.
422  * 
423  * @param type  The type to query.
424  */
425 size_t
426 bhnd_nvram_type_width(bhnd_nvram_type type)
427 {
428         switch (type) {
429         case BHND_NVRAM_TYPE_STRING:
430         case BHND_NVRAM_TYPE_STRING_ARRAY:
431         case BHND_NVRAM_TYPE_DATA:
432                 return (0);
433
434         case BHND_NVRAM_TYPE_NULL:
435                 return (0);
436
437         case BHND_NVRAM_TYPE_BOOL:
438         case BHND_NVRAM_TYPE_BOOL_ARRAY:
439                 return (sizeof(bhnd_nvram_bool_t));
440
441         case BHND_NVRAM_TYPE_CHAR:
442         case BHND_NVRAM_TYPE_CHAR_ARRAY:
443         case BHND_NVRAM_TYPE_UINT8:
444         case BHND_NVRAM_TYPE_UINT8_ARRAY:
445         case BHND_NVRAM_TYPE_INT8:
446         case BHND_NVRAM_TYPE_INT8_ARRAY:
447                 return (sizeof(uint8_t));
448
449         case BHND_NVRAM_TYPE_UINT16:
450         case BHND_NVRAM_TYPE_UINT16_ARRAY:
451         case BHND_NVRAM_TYPE_INT16:
452         case BHND_NVRAM_TYPE_INT16_ARRAY:
453                 return (sizeof(uint16_t));
454
455         case BHND_NVRAM_TYPE_UINT32:
456         case BHND_NVRAM_TYPE_UINT32_ARRAY:
457         case BHND_NVRAM_TYPE_INT32:
458         case BHND_NVRAM_TYPE_INT32_ARRAY:
459                 return (sizeof(uint32_t));
460
461         case BHND_NVRAM_TYPE_UINT64:
462         case BHND_NVRAM_TYPE_UINT64_ARRAY:
463         case BHND_NVRAM_TYPE_INT64:
464         case BHND_NVRAM_TYPE_INT64_ARRAY:
465                 return (sizeof(uint64_t));
466         }
467
468         /* Quiesce gcc4.2 */
469         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
470 }
471
472 /**
473  * Return the native host alignment for values of @p type.
474  * 
475  * @param type The type to query.
476  */
477 size_t
478 bhnd_nvram_type_host_align(bhnd_nvram_type type)
479 {
480         switch (type) {
481         case BHND_NVRAM_TYPE_CHAR:
482         case BHND_NVRAM_TYPE_CHAR_ARRAY:
483         case BHND_NVRAM_TYPE_DATA:
484         case BHND_NVRAM_TYPE_STRING:
485         case BHND_NVRAM_TYPE_STRING_ARRAY:
486                 return (_Alignof(uint8_t));
487         case BHND_NVRAM_TYPE_BOOL:
488         case BHND_NVRAM_TYPE_BOOL_ARRAY: {
489                 _Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
490                     "bhnd_nvram_bool_t must be uint8-representable");
491                 return (_Alignof(uint8_t));
492         }
493         case BHND_NVRAM_TYPE_NULL:
494                 return (1);
495         case BHND_NVRAM_TYPE_UINT8:
496         case BHND_NVRAM_TYPE_UINT8_ARRAY:
497                 return (_Alignof(uint8_t));
498         case BHND_NVRAM_TYPE_UINT16:
499         case BHND_NVRAM_TYPE_UINT16_ARRAY:
500                 return (_Alignof(uint16_t));
501         case BHND_NVRAM_TYPE_UINT32:
502         case BHND_NVRAM_TYPE_UINT32_ARRAY:
503                 return (_Alignof(uint32_t));
504         case BHND_NVRAM_TYPE_UINT64:
505         case BHND_NVRAM_TYPE_UINT64_ARRAY:
506                 return (_Alignof(uint64_t));
507         case BHND_NVRAM_TYPE_INT8:
508         case BHND_NVRAM_TYPE_INT8_ARRAY:
509                 return (_Alignof(int8_t));
510         case BHND_NVRAM_TYPE_INT16:
511         case BHND_NVRAM_TYPE_INT16_ARRAY:
512                 return (_Alignof(int16_t));
513         case BHND_NVRAM_TYPE_INT32:
514         case BHND_NVRAM_TYPE_INT32_ARRAY:
515                 return (_Alignof(int32_t));
516         case BHND_NVRAM_TYPE_INT64:
517         case BHND_NVRAM_TYPE_INT64_ARRAY:
518                 return (_Alignof(int64_t));
519         }
520
521         /* Quiesce gcc4.2 */
522         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
523 }
524
525 /**
526  * Iterate over all strings in the @p inp string array (@see
527  * BHNF_NVRAM_TYPE_STRING_ARRAY).
528  *
529  * @param               inp     The string array to be iterated. This must be a
530  *                              buffer of one or more NUL-terminated strings.
531  * @param               ilen    The size, in bytes, of @p inp, including any
532  *                              terminating NUL character(s).
533  * @param               prev    The pointer previously returned by
534  *                              bhnd_nvram_string_array_next(), or NULL to begin
535  *                              iteration.
536 * @param[in,out]        olen    If @p prev is non-NULL, @p olen must be a
537  *                              pointer to the length previously returned by
538  *                              bhnd_nvram_string_array_next(). On success, will
539  *                              be set to the next element's length, in bytes.
540  *
541  * @retval non-NULL     A reference to the next NUL-terminated string
542  * @retval NULL         If the end of the string array is reached.
543  */
544 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 /**
1044  * Parse a field value, returning the actual pointer to the first
1045  * non-whitespace character and the total size of the field.
1046  *
1047  * @param[in,out] inp The field string to parse. Will be updated to point
1048  * at the first non-whitespace character found.
1049  * @param ilen The length of @p inp, in bytes.
1050  * @param delim The field delimiter to search for.
1051  *
1052  * @return Returns the actual size of the field data.
1053  */
1054 size_t
1055 bhnd_nvram_parse_field(const char **inp, size_t ilen, char delim)
1056 {
1057         const char      *p, *sp;
1058         
1059         /* Skip any leading whitespace */
1060         for (sp = *inp; (size_t)(sp-*inp) < ilen && bhnd_nv_isspace(*sp); sp++)
1061                 continue;
1062         
1063         *inp = sp;
1064         
1065         /* Find the last field character */
1066         for (p = *inp; (size_t)(p - *inp) < ilen; p++) {
1067                 if (*p == delim || *p == '\0')
1068                         break;
1069         }
1070         
1071         return (p - *inp);
1072 }
1073
1074 /**
1075  * Parse a field value, returning the actual pointer to the first
1076  * non-whitespace character and the total size of the field, minus
1077  * any trailing whitespace.
1078  *
1079  * @param[in,out] inp The field string to parse. Will be updated to point
1080  * at the first non-whitespace character found.
1081  * @param ilen The length of the parsed field, in bytes, excluding the
1082  * field elimiter and any trailing whitespace.
1083  * @param delim The field delimiter to search for.
1084  *
1085  * @return Returns the actual size of the field data.
1086  */
1087 size_t
1088 bhnd_nvram_trim_field(const char **inp, size_t ilen, char delim)
1089 {
1090         const char      *sp;
1091         size_t           plen;
1092         
1093         plen = bhnd_nvram_parse_field(inp, ilen, delim);
1094         
1095         /* Trim trailing whitespace */
1096         sp = *inp;
1097         while (plen > 0) {
1098                 if (!bhnd_nv_isspace(*(sp + plen - 1)))
1099                         break;
1100                 
1101                 plen--;
1102         }
1103         
1104         return (plen);
1105 }