1 /*- 2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/param.h> 31 32 #ifdef _KERNEL 33 34 #include <sys/ctype.h> 35 #include <sys/kernel.h> 36 #include <sys/limits.h> 37 #include <sys/malloc.h> 38 #include <sys/systm.h> 39 40 #include <machine/_inttypes.h> 41 42 #else /* !_KERNEL */ 43 44 #include <ctype.h> 45 #include <errno.h> 46 #include <inttypes.h> 47 #include <limits.h> 48 #include <stdbool.h> 49 #include <stdio.h> 50 #include <stdint.h> 51 #include <stdlib.h> 52 #include <string.h> 53 54 #endif /* _KERNEL */ 55 56 #include "bhnd_nvram_io.h" 57 #include "bhnd_nvram_private.h" 58 #include "bhnd_nvram_value.h" 59 60 #include "bhnd_nvram_map_data.h" 61 62 /* 63 * Common NVRAM/SPROM support, including NVRAM variable map 64 * lookup. 65 */ 66 67 #ifdef _KERNEL 68 MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data"); 69 #endif 70 71 /* 72 * CRC-8 lookup table used to checksum SPROM and NVRAM data via 73 * bhnd_nvram_crc8(). 74 * 75 * Generated with following parameters: 76 * polynomial: CRC-8 (x^8 + x^7 + x^6 + x^4 + x^2 + 1) 77 * reflected bits: false 78 * reversed: true 79 */ 80 const uint8_t bhnd_nvram_crc8_tab[] = { 81 0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b, 0x4a, 0xbd, 0xf3, 82 0x04, 0x6f, 0x98, 0xd6, 0x21, 0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46, 83 0x08, 0xff, 0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5, 0x7f, 84 0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14, 0x35, 0xc2, 0x8c, 0x7b, 85 0x10, 0xe7, 0xa9, 0x5e, 0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77, 86 0x80, 0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca, 0xfe, 0x09, 87 0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95, 0xb4, 0x43, 0x0d, 0xfa, 0x91, 88 0x66, 0x28, 0xdf, 0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01, 89 0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b, 0x81, 0x76, 0x38, 90 0xcf, 0xa4, 0x53, 0x1d, 0xea, 0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19, 91 0x57, 0xa0, 0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e, 0x5f, 92 0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34, 0xab, 0x5c, 0x12, 0xe5, 93 0x8e, 0x79, 0x37, 0xc0, 0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d, 94 0x8a, 0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54, 0x75, 0x82, 95 0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e, 0xd4, 0x23, 0x6d, 0x9a, 0xf1, 96 0x06, 0x48, 0xbf, 0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5, 97 0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b, 0x0a, 0xfd, 0xb3, 98 0x44, 0x2f, 0xd8, 0x96, 0x61, 0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87, 99 0xc9, 0x3e, 0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74, 0xc1, 100 0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa, 0x8b, 0x7c, 0x32, 0xc5, 101 0xae, 0x59, 0x17, 0xe0, 0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6, 102 0x41, 0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b, 0xbe, 0x49, 103 0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5, 0xf4, 0x03, 0x4d, 0xba, 0xd1, 104 0x26, 0x68, 0x9f 105 }; 106 107 /** 108 * Return a human readable name for @p type. 109 * 110 * @param type The type to query. 111 */ 112 const char * 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