]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/nvram/bhnd_nvram_subr.c
Upgrade to OpenSSH 7.6p1. This will be followed shortly by 7.7p1.
[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  * BHND_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  * @see BHND_NVRAM_TYPE_STRING_ARRAY
545  */
546 const char *
547 bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev,
548     size_t *olen)
549 {
550         return (bhnd_nvram_value_array_next(inp, ilen,
551             BHND_NVRAM_TYPE_STRING_ARRAY, prev, olen));
552 }
553
554 /* used by bhnd_nvram_find_vardefn() */
555 static int
556 bhnd_nvram_find_vardefn_compare(const void *key, const void *rhs)
557 {
558         const struct bhnd_nvram_vardefn *r = rhs;
559
560         return (strcmp((const char *)key, r->name));
561 }
562
563 /**
564  * Find and return the variable definition for @p varname, if any.
565  * 
566  * @param varname variable name
567  * 
568  * @retval bhnd_nvram_vardefn If a valid definition for @p varname is found.
569  * @retval NULL If no definition for @p varname is found. 
570  */
571 const struct bhnd_nvram_vardefn *
572 bhnd_nvram_find_vardefn(const char *varname)
573 {
574         return (bsearch(varname, bhnd_nvram_vardefns, bhnd_nvram_num_vardefns,
575             sizeof(bhnd_nvram_vardefns[0]), bhnd_nvram_find_vardefn_compare));
576 }
577
578 /**
579  * Return the variable ID for a variable definition.
580  * 
581  * @param defn Variable definition previously returned by
582  * bhnd_nvram_find_vardefn() or bhnd_nvram_get_vardefn().
583  */
584 size_t
585 bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn *defn)
586 {
587         BHND_NV_ASSERT(
588             defn >= bhnd_nvram_vardefns &&
589             defn <= &bhnd_nvram_vardefns[bhnd_nvram_num_vardefns-1],
590             ("invalid variable definition pointer %p", defn));
591
592         return (defn - bhnd_nvram_vardefns);
593 }
594
595 /**
596  * Return the variable definition with the given @p id, or NULL
597  * if no such variable ID is defined.
598  * 
599  * @param id variable ID.
600  *
601  * @retval bhnd_nvram_vardefn If a valid definition for @p id is found.
602  * @retval NULL If no definition for @p id is found. 
603  */
604 const struct bhnd_nvram_vardefn *
605 bhnd_nvram_get_vardefn(size_t id)
606 {
607         if (id >= bhnd_nvram_num_vardefns)
608                 return (NULL);
609
610         return (&bhnd_nvram_vardefns[id]);
611 }
612
613 /**
614  * Validate an NVRAM variable name.
615  * 
616  * Scans for special characters (path delimiters, value delimiters, path
617  * alias prefixes), returning false if the given name cannot be used
618  * as a relative NVRAM key.
619  *
620  * @param name A relative NVRAM variable name to validate.
621  * 
622  * @retval true If @p name is a valid relative NVRAM key.
623  * @retval false If @p name should not be used as a relative NVRAM key.
624  */
625 bool
626 bhnd_nvram_validate_name(const char *name)
627 {
628         /* Reject path-prefixed variable names */
629         if (bhnd_nvram_trim_path_name(name) != name)
630                 return (false);
631
632         /* Reject device path alias declarations (devpath[1-9][0-9]*.*\0) */
633         if (strncmp(name, "devpath", strlen("devpath")) == 0) {
634                 const char      *p;
635                 char            *endp;
636
637                 /* Check for trailing [1-9][0-9]* */
638                 p = name + strlen("devpath");
639                 strtoul(p, &endp, 10);
640                 if (endp != p)
641                         return (false);
642         }
643
644         /* Scan for [^A-Za-z_0-9] */
645         for (const char *p = name; *p != '\0'; p++) {
646                 switch (*p) {
647                 /* [0-9_] */
648                 case '0': case '1': case '2': case '3': case '4':
649                 case '5': case '6': case '7': case '8': case '9':
650                 case '_':
651                         break;
652
653                 /* [A-Za-z] */
654                 default:
655                         if (!bhnd_nv_isalpha(*p))
656                                 return (false);
657                         break;
658                 }
659         }
660
661         return (true);
662 }
663
664 /**
665  * Parses the string in the optionally NUL-terminated @p str to as an integer
666  * value of @p otype, accepting any integer format supported by the standard
667  * strtoul().
668  * 
669  * - Any leading whitespace in @p str -- as defined by the equivalent of
670  *   calling isspace_l() with an ASCII locale -- will be ignored.
671  * - A @p str may be prefixed with a single optional '+' or '-' sign denoting
672  *   signedness.
673  * - A hexadecimal @p str may include an '0x' or '0X' prefix, denoting that a
674  *   base 16 integer follows.
675  * - An octal @p str may include a '0' prefix, denoting that an octal integer
676  *   follows.
677  * 
678  * If a @p base of 0 is specified, the base will be determined according
679  * to the string's initial prefix, as per strtoul()'s documented behavior.
680  *
681  * When parsing a base 16 integer to a signed representation, if no explicit
682  * sign prefix is given, the string will be parsed as the raw two's complement
683  * representation of the signed integer value.
684  *
685  * @param               str     The string to be parsed.
686  * @param               maxlen  The maximum number of bytes to be read in
687  *                              @p str.
688  * @param               base    The input string's base (2-36), or 0.
689  * @param[out]          nbytes  On success or failure, will be set to the total
690  *                              number of parsed bytes. If the total number of
691  *                              bytes is not desired, a NULL pointer may be
692  *                              provided.
693  * @param[out]          outp    On success, the parsed integer value will be
694  *                              written to @p outp. This argment may be NULL if
695  *                              the value is not desired.
696  * @param[in,out]       olen    The capacity of @p outp. On success, will be set
697  *                              to the actual size of the requested value.
698  * @param               otype   The integer type to be parsed.
699  *
700  * @retval 0            success
701  * @retval EINVAL       if an invalid @p base is specified.
702  * @retval EINVAL       if an unsupported (or non-integer) @p otype is
703  *                      specified.
704  * @retval ENOMEM       If @p outp is non-NULL and a buffer of @p olen is too
705  *                      small to hold the requested value.
706  * @retval EFTYPE       if @p str cannot be parsed as an integer of @p base.
707  * @retval ERANGE       If the integer parsed from @p str is too large to be
708  *                      represented as a value of @p otype.
709  */
710 int
711 bhnd_nvram_parse_int(const char *str, size_t maxlen,  u_int base,
712     size_t *nbytes, void *outp, size_t *olen, bhnd_nvram_type otype)
713 {
714         uint64_t        value;
715         uint64_t        carry_max, value_max;
716         uint64_t        type_max;
717         size_t          limit, local_nbytes;
718         size_t          ndigits;
719         bool            negative, sign, twos_compl;
720
721         /* Must be an integer type */
722         if (!bhnd_nvram_is_int_type(otype))
723                 return (EINVAL);
724
725         /* Determine output byte limit */
726         if (outp != NULL)
727                 limit = *olen;
728         else
729                 limit = 0;
730
731         /* We always need a byte count. If the caller provides a NULL nbytes,
732          * track our position in a stack variable */
733         if (nbytes == NULL)
734                 nbytes = &local_nbytes;
735
736         value = 0;
737         ndigits = 0;
738         *nbytes = 0;
739         negative = false;
740         sign = false;
741
742         /* Validate the specified base */
743         if (base != 0 && !(base >= 2 && base <= 36))
744                 return (EINVAL);
745
746         /* Skip any leading whitespace */
747         for (; *nbytes < maxlen; (*nbytes)++) {
748                 if (!bhnd_nv_isspace(str[*nbytes]))
749                         break;
750         }
751
752         /* Empty string? */
753         if (*nbytes == maxlen)
754                 return (EFTYPE);
755
756         /* Parse and skip sign */
757         if (str[*nbytes] == '-') {
758                 negative = true;
759                 sign = true;
760                 (*nbytes)++;
761         } else if (str[*nbytes] == '+') {
762                 sign = true;
763                 (*nbytes)++;
764         }
765
766         /* Truncated after sign character? */
767         if (*nbytes == maxlen)
768                 return (EFTYPE);
769
770         /* Identify (or validate) hex base, skipping 0x/0X prefix */
771         if (base == 16 || base == 0) {
772                 /* Check for (and skip) 0x/0X prefix */
773                 if (maxlen - *nbytes >= 2 && str[*nbytes] == '0' &&
774                     (str[*nbytes+1] == 'x' || str[*nbytes+1] == 'X'))
775                 {
776                         base = 16;
777                         (*nbytes) += 2;
778                 }
779         }
780
781         /* Truncated after hex prefix? */
782         if (*nbytes == maxlen)
783                 return (EFTYPE);
784
785         /* Differentiate decimal/octal by looking for a leading 0 */
786         if (base == 0) {
787                 if (str[*nbytes] == '0') {
788                         base = 8;
789                 } else {
790                         base = 10;
791                 }
792         }
793
794         /* Only enable twos-compliment signed integer parsing enabled if the
795          * input is base 16, and no explicit sign prefix was provided */
796         if (!sign && base == 16)
797                 twos_compl = true;
798         else
799                 twos_compl = false;
800
801         /* Determine the maximum value representable by the requested type */
802         switch (otype) {
803         case BHND_NVRAM_TYPE_CHAR:
804         case BHND_NVRAM_TYPE_UINT8:
805                 type_max = (uint64_t)UINT8_MAX;
806                 break;
807         case BHND_NVRAM_TYPE_UINT16:
808                 type_max = (uint64_t)UINT16_MAX;
809                 break;
810         case BHND_NVRAM_TYPE_UINT32:
811                 type_max = (uint64_t)UINT32_MAX;
812                 break;
813         case BHND_NVRAM_TYPE_UINT64:
814                 type_max = (uint64_t)UINT64_MAX;
815                 break;
816
817         case BHND_NVRAM_TYPE_INT8:
818                 if (twos_compl)
819                         type_max = (uint64_t)UINT8_MAX;
820                 else if (negative)
821                         type_max = -(uint64_t)INT8_MIN;
822                 else
823                         type_max = (uint64_t)INT8_MAX;
824                 break;
825
826         case BHND_NVRAM_TYPE_INT16:
827                 if (twos_compl)
828                         type_max = (uint64_t)UINT16_MAX;
829                 else if (negative)
830                         type_max = -(uint64_t)INT16_MIN;
831                 else
832                         type_max = (uint64_t)INT16_MAX;
833                 break;
834
835         case BHND_NVRAM_TYPE_INT32:
836                 if (twos_compl)
837                         type_max = (uint64_t)UINT32_MAX;
838                 else if (negative)
839                         type_max = -(uint64_t)INT32_MIN;
840                 else
841                         type_max = (uint64_t)INT32_MAX;
842                 break;
843
844         case BHND_NVRAM_TYPE_INT64:
845                 if (twos_compl)
846                         type_max = (uint64_t)UINT64_MAX;
847                 else if (negative)
848                         type_max = -(uint64_t)INT64_MIN;
849                 else
850                         type_max = (uint64_t)INT64_MAX;
851                 break;
852
853         default:
854                 BHND_NV_LOG("unsupported integer type: %d\n", otype);
855                 return (EINVAL);
856         }
857
858         /* The maximum value after which an additional carry would overflow */
859         value_max = type_max / (uint64_t)base;
860
861         /* The maximum carry value given a value equal to value_max */
862         carry_max = type_max % (uint64_t)base;
863
864         /* Consume input until we hit maxlen or a non-digit character */
865         for (; *nbytes < maxlen; (*nbytes)++) {
866                 u_long  carry;
867                 char    c;
868
869                 /* Parse carry value */
870                 c = str[*nbytes];
871                 if (bhnd_nv_isdigit(c)) {
872                         carry = c - '0';
873                 } else if (bhnd_nv_isxdigit(c)) {
874                         if (bhnd_nv_isupper(c))
875                                 carry = (c - 'A') + 10;
876                         else
877                                 carry = (c - 'a') + 10;
878                 } else {
879                         /* Hit first non-digit character */
880                         break;
881                 }
882
883                 /* If carry is outside the base, it's not a valid digit
884                  * in the current parse context; consider it a non-digit
885                  * character */
886                 if (carry >= (uint64_t)base)
887                         break;
888
889                 /* Increment count of parsed digits */
890                 ndigits++;
891
892                 if (value > value_max) {
893                         /* -Any- carry value would overflow */
894                         return (ERANGE);
895                 } else if (value == value_max && carry > carry_max) {
896                         /* -This- carry value would overflow */
897                         return (ERANGE);
898                 }
899
900                 value *= (uint64_t)base;
901                 value += carry;
902         }
903
904         /* If we hit a non-digit character before parsing the first digit,
905          * we hit an empty integer string. */
906         if (ndigits == 0)
907                 return (EFTYPE);
908
909         if (negative)
910                 value = -value;
911
912         /* Provide (and verify) required length */
913         *olen = bhnd_nvram_type_width(otype);
914         if (outp == NULL)
915                 return (0);
916         else if (limit < *olen)
917                 return (ENOMEM);
918
919         /* Provide result */
920         switch (otype) {
921         case BHND_NVRAM_TYPE_CHAR:
922         case BHND_NVRAM_TYPE_UINT8:
923                 *(uint8_t *)outp = (uint8_t)value;
924                 break;
925         case BHND_NVRAM_TYPE_UINT16:
926                 *(uint16_t *)outp = (uint16_t)value;
927                 break;
928         case BHND_NVRAM_TYPE_UINT32:
929                 *(uint32_t *)outp = (uint32_t)value;
930                 break;
931         case BHND_NVRAM_TYPE_UINT64:
932                 *(uint64_t *)outp = (uint64_t)value;
933                 break;
934
935         case BHND_NVRAM_TYPE_INT8:
936                 *(int8_t *)outp = (int8_t)(int64_t)value;
937                 break;
938         case BHND_NVRAM_TYPE_INT16:
939                 *(int16_t *)outp = (int16_t)(int64_t)value;
940                 break;
941         case BHND_NVRAM_TYPE_INT32:
942                 *(int32_t *)outp = (int32_t)(int64_t)value;
943                 break;
944         case BHND_NVRAM_TYPE_INT64:
945                 *(int64_t *)outp = (int64_t)value;
946                 break;
947         default:
948                 /* unreachable */
949                 BHND_NV_PANIC("unhandled type %d\n", otype);
950         }
951
952         return (0);
953 }
954
955 /**
956  * Trim leading path (pci/1/1) or path alias (0:) prefix from @p name, if any,
957  * returning a pointer to the start of the relative variable name.
958  * 
959  * @par Examples
960  * 
961  * - "/foo"             -> "foo"
962  * - "dev/pci/foo"      -> "foo"
963  * - "0:foo"            -> "foo"
964  * - "foo"              -> "foo"
965  * 
966  * @param name The string to be trimmed.
967  * 
968  * @return A pointer to the start of the relative variable name in @p name.
969  */
970 const char *
971 bhnd_nvram_trim_path_name(const char *name)
972 {
973         char *endp;
974
975         /* path alias prefix? (0:varname) */
976         if (bhnd_nv_isdigit(*name)) {
977                 /* Parse '0...:' alias prefix, if it exists */
978                 strtoul(name, &endp, 10);
979                 if (endp != name && *endp == ':') {
980                         /* Variable name follows 0: prefix */
981                         return (endp+1);
982                 }
983         }
984
985         /* device path prefix? (pci/1/1/varname) */
986         if ((endp = strrchr(name, '/')) != NULL) {
987                 /* Variable name follows the final path separator '/' */
988                 return (endp+1);
989         }
990
991         /* variable name is not prefixed */
992         return (name);
993 }
994
995 /**
996  * Parse a 'name=value' string.
997  * 
998  * @param env The string to be parsed.
999  * @param env_len The length of @p envp.
1000  * @param delim The delimiter used in @p envp. This will generally be '='.
1001  * @param[out] name If not NULL, a pointer to the name string. This argument
1002  * may be NULL.
1003  * @param[out] name_len On success, the length of the name substring. This
1004  * argument may be NULL.
1005  * @param[out] value On success, a pointer to the value substring. This argument
1006  * may be NULL.
1007  * @param[out] value_len On success, the length of the value substring. This
1008  * argument may be NULL.
1009  * 
1010  * @retval 0 success
1011  * @retval EINVAL if parsing @p envp fails.
1012  */
1013 int
1014 bhnd_nvram_parse_env(const char *env, size_t env_len, char delim,
1015     const char **name, size_t *name_len, const char **value, size_t *value_len)
1016 {
1017         const char *p;
1018
1019         /* Name */
1020         if ((p = memchr(env, delim, env_len)) == NULL) {
1021                 BHND_NV_LOG("delimiter '%c' not found in '%.*s'\n", delim,
1022                     BHND_NV_PRINT_WIDTH(env_len), env);
1023                 return (EINVAL);
1024         }
1025
1026         /* Name */
1027         if (name != NULL)
1028                 *name = env;
1029         if (name_len != NULL)
1030                 *name_len = p - env;
1031
1032         /* Skip delim */
1033         p++;
1034
1035         /* Value */
1036         if (value != NULL)
1037                 *value = p;
1038         if (value_len != NULL)
1039                 *value_len = env_len - (p - env);
1040
1041         return (0);
1042 }
1043
1044
1045 /**
1046  * Parse a field value, returning the actual pointer to the first
1047  * non-whitespace character and the total size of the field.
1048  *
1049  * @param[in,out] inp The field string to parse. Will be updated to point
1050  * at the first non-whitespace character found.
1051  * @param ilen The length of @p inp, in bytes.
1052  * @param delim The field delimiter to search for.
1053  *
1054  * @return Returns the actual size of the field data.
1055  */
1056 size_t
1057 bhnd_nvram_parse_field(const char **inp, size_t ilen, char delim)
1058 {
1059         const char      *p, *sp;
1060         
1061         /* Skip any leading whitespace */
1062         for (sp = *inp; (size_t)(sp-*inp) < ilen && bhnd_nv_isspace(*sp); sp++)
1063                 continue;
1064         
1065         *inp = sp;
1066         
1067         /* Find the last field character */
1068         for (p = *inp; (size_t)(p - *inp) < ilen; p++) {
1069                 if (*p == delim || *p == '\0')
1070                         break;
1071         }
1072         
1073         return (p - *inp);
1074 }
1075
1076 /**
1077  * Parse a field value, returning the actual pointer to the first
1078  * non-whitespace character and the total size of the field, minus
1079  * any trailing whitespace.
1080  *
1081  * @param[in,out] inp The field string to parse. Will be updated to point
1082  * at the first non-whitespace character found.
1083  * @param ilen The length of the parsed field, in bytes, excluding the
1084  * field elimiter and any trailing whitespace.
1085  * @param delim The field delimiter to search for.
1086  *
1087  * @return Returns the actual size of the field data.
1088  */
1089 size_t
1090 bhnd_nvram_trim_field(const char **inp, size_t ilen, char delim)
1091 {
1092         const char      *sp;
1093         size_t           plen;
1094         
1095         plen = bhnd_nvram_parse_field(inp, ilen, delim);
1096         
1097         /* Trim trailing whitespace */
1098         sp = *inp;
1099         while (plen > 0) {
1100                 if (!bhnd_nv_isspace(*(sp + plen - 1)))
1101                         break;
1102                 
1103                 plen--;
1104         }
1105         
1106         return (plen);
1107 }