Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bhnd/nvram/bhnd_nvram_subr.c
39536 views
1
/*-
2
* Copyright (c) 2015-2016 Landon Fuller <[email protected]>
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 *
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
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
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
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
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
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
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
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
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 *
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
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 *
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
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 *
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
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
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 *
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
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
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
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
1105