xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_subr.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
177cb4d3eSLandon J. Fuller /*-
277cb4d3eSLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
377cb4d3eSLandon J. Fuller  * All rights reserved.
477cb4d3eSLandon J. Fuller  *
577cb4d3eSLandon J. Fuller  * Redistribution and use in source and binary forms, with or without
677cb4d3eSLandon J. Fuller  * modification, are permitted provided that the following conditions
777cb4d3eSLandon J. Fuller  * are met:
877cb4d3eSLandon J. Fuller  * 1. Redistributions of source code must retain the above copyright
977cb4d3eSLandon J. Fuller  *    notice, this list of conditions and the following disclaimer,
1077cb4d3eSLandon J. Fuller  *    without modification.
1177cb4d3eSLandon J. Fuller  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1277cb4d3eSLandon J. Fuller  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1377cb4d3eSLandon J. Fuller  *    redistribution must be conditioned upon including a substantially
1477cb4d3eSLandon J. Fuller  *    similar Disclaimer requirement for further binary redistribution.
1577cb4d3eSLandon J. Fuller  *
1677cb4d3eSLandon J. Fuller  * NO WARRANTY
1777cb4d3eSLandon J. Fuller  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1877cb4d3eSLandon J. Fuller  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1977cb4d3eSLandon J. Fuller  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2077cb4d3eSLandon J. Fuller  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2177cb4d3eSLandon J. Fuller  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2277cb4d3eSLandon J. Fuller  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2377cb4d3eSLandon J. Fuller  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2477cb4d3eSLandon J. Fuller  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2577cb4d3eSLandon J. Fuller  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2677cb4d3eSLandon J. Fuller  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2777cb4d3eSLandon J. Fuller  * THE POSSIBILITY OF SUCH DAMAGES.
2877cb4d3eSLandon J. Fuller  */
2977cb4d3eSLandon J. Fuller 
3077cb4d3eSLandon J. Fuller #include <sys/param.h>
3177cb4d3eSLandon J. Fuller 
3277cb4d3eSLandon J. Fuller #ifdef _KERNEL
3377cb4d3eSLandon J. Fuller 
3477cb4d3eSLandon J. Fuller #include <sys/ctype.h>
3577cb4d3eSLandon J. Fuller #include <sys/kernel.h>
3677cb4d3eSLandon J. Fuller #include <sys/limits.h>
3777cb4d3eSLandon J. Fuller #include <sys/malloc.h>
3877cb4d3eSLandon J. Fuller #include <sys/systm.h>
3977cb4d3eSLandon J. Fuller 
4077cb4d3eSLandon J. Fuller #include <machine/_inttypes.h>
4177cb4d3eSLandon J. Fuller 
4277cb4d3eSLandon J. Fuller #else /* !_KERNEL */
4377cb4d3eSLandon J. Fuller 
4477cb4d3eSLandon J. Fuller #include <ctype.h>
4577cb4d3eSLandon J. Fuller #include <errno.h>
4677cb4d3eSLandon J. Fuller #include <inttypes.h>
4777cb4d3eSLandon J. Fuller #include <limits.h>
4877cb4d3eSLandon J. Fuller #include <stdbool.h>
4977cb4d3eSLandon J. Fuller #include <stdio.h>
5077cb4d3eSLandon J. Fuller #include <stdint.h>
5177cb4d3eSLandon J. Fuller #include <stdlib.h>
5277cb4d3eSLandon J. Fuller #include <string.h>
5377cb4d3eSLandon J. Fuller 
5477cb4d3eSLandon J. Fuller #endif /* _KERNEL */
5577cb4d3eSLandon J. Fuller 
5677cb4d3eSLandon J. Fuller #include "bhnd_nvram_io.h"
5777cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
5877cb4d3eSLandon J. Fuller #include "bhnd_nvram_value.h"
5977cb4d3eSLandon J. Fuller 
6077cb4d3eSLandon J. Fuller #include "bhnd_nvram_map_data.h"
6177cb4d3eSLandon J. Fuller 
6277cb4d3eSLandon J. Fuller /*
6377cb4d3eSLandon J. Fuller  * Common NVRAM/SPROM support, including NVRAM variable map
6477cb4d3eSLandon J. Fuller  * lookup.
6577cb4d3eSLandon J. Fuller  */
6677cb4d3eSLandon J. Fuller 
6777cb4d3eSLandon J. Fuller #ifdef _KERNEL
6877cb4d3eSLandon J. Fuller MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data");
6977cb4d3eSLandon J. Fuller #endif
7077cb4d3eSLandon J. Fuller 
7177cb4d3eSLandon J. Fuller /*
7277cb4d3eSLandon J. Fuller  * CRC-8 lookup table used to checksum SPROM and NVRAM data via
7377cb4d3eSLandon J. Fuller  * bhnd_nvram_crc8().
7477cb4d3eSLandon J. Fuller  *
7577cb4d3eSLandon J. Fuller  * Generated with following parameters:
7677cb4d3eSLandon J. Fuller  * 	polynomial:	CRC-8 (x^8 + x^7 + x^6 + x^4 + x^2 + 1)
7777cb4d3eSLandon J. Fuller  * 	reflected bits:	false
7877cb4d3eSLandon J. Fuller  * 	reversed:	true
7977cb4d3eSLandon J. Fuller  */
8077cb4d3eSLandon J. Fuller const uint8_t bhnd_nvram_crc8_tab[] = {
8177cb4d3eSLandon J. Fuller 	0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b, 0x4a, 0xbd, 0xf3,
8277cb4d3eSLandon J. Fuller 	0x04, 0x6f, 0x98, 0xd6, 0x21, 0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46,
8377cb4d3eSLandon J. Fuller 	0x08, 0xff, 0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5, 0x7f,
8477cb4d3eSLandon J. Fuller 	0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14, 0x35, 0xc2, 0x8c, 0x7b,
8577cb4d3eSLandon J. Fuller 	0x10, 0xe7, 0xa9, 0x5e, 0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77,
8677cb4d3eSLandon J. Fuller 	0x80, 0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca, 0xfe, 0x09,
8777cb4d3eSLandon J. Fuller 	0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95, 0xb4, 0x43, 0x0d, 0xfa, 0x91,
8877cb4d3eSLandon J. Fuller 	0x66, 0x28, 0xdf, 0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01,
8977cb4d3eSLandon J. Fuller 	0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b, 0x81, 0x76, 0x38,
9077cb4d3eSLandon J. Fuller 	0xcf, 0xa4, 0x53, 0x1d, 0xea, 0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19,
9177cb4d3eSLandon J. Fuller 	0x57, 0xa0, 0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e, 0x5f,
9277cb4d3eSLandon J. Fuller 	0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34, 0xab, 0x5c, 0x12, 0xe5,
9377cb4d3eSLandon J. Fuller 	0x8e, 0x79, 0x37, 0xc0, 0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d,
9477cb4d3eSLandon J. Fuller 	0x8a, 0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54, 0x75, 0x82,
9577cb4d3eSLandon J. Fuller 	0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e, 0xd4, 0x23, 0x6d, 0x9a, 0xf1,
9677cb4d3eSLandon J. Fuller 	0x06, 0x48, 0xbf, 0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5,
9777cb4d3eSLandon J. Fuller 	0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b, 0x0a, 0xfd, 0xb3,
9877cb4d3eSLandon J. Fuller 	0x44, 0x2f, 0xd8, 0x96, 0x61, 0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87,
9977cb4d3eSLandon J. Fuller 	0xc9, 0x3e, 0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74, 0xc1,
10077cb4d3eSLandon J. Fuller 	0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa, 0x8b, 0x7c, 0x32, 0xc5,
10177cb4d3eSLandon J. Fuller 	0xae, 0x59, 0x17, 0xe0, 0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6,
10277cb4d3eSLandon J. Fuller 	0x41, 0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b, 0xbe, 0x49,
10377cb4d3eSLandon J. Fuller 	0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5, 0xf4, 0x03, 0x4d, 0xba, 0xd1,
10477cb4d3eSLandon J. Fuller 	0x26, 0x68, 0x9f
10577cb4d3eSLandon J. Fuller };
10677cb4d3eSLandon J. Fuller 
10777cb4d3eSLandon J. Fuller /**
10877cb4d3eSLandon J. Fuller  * Return a human readable name for @p type.
10977cb4d3eSLandon J. Fuller  *
11077cb4d3eSLandon J. Fuller  * @param type The type to query.
11177cb4d3eSLandon J. Fuller  */
11277cb4d3eSLandon J. Fuller const char *
bhnd_nvram_type_name(bhnd_nvram_type type)11377cb4d3eSLandon J. Fuller bhnd_nvram_type_name(bhnd_nvram_type type)
11477cb4d3eSLandon J. Fuller {
11577cb4d3eSLandon J. Fuller 	switch (type) {
11677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
11777cb4d3eSLandon J. Fuller 		return ("uint8");
11877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
11977cb4d3eSLandon J. Fuller 		return ("uint16");
12077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
12177cb4d3eSLandon J. Fuller 		return ("uint32");
12277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
12377cb4d3eSLandon J. Fuller 		return ("uint64");
12477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
12577cb4d3eSLandon J. Fuller 		return ("char");
12677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
12777cb4d3eSLandon J. Fuller 		return ("int8");
12877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
12977cb4d3eSLandon J. Fuller 		return ("int16");
13077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
13177cb4d3eSLandon J. Fuller 		return ("int32");
13277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
13377cb4d3eSLandon J. Fuller 		return ("int64");
13477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
13577cb4d3eSLandon J. Fuller 		return ("string");
1366cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
1376cffadf0SLandon J. Fuller 		return ("bool");
1386cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
1396cffadf0SLandon J. Fuller 		return ("null");
1406cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
1416cffadf0SLandon J. Fuller 		return ("data");
14277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
14377cb4d3eSLandon J. Fuller 		return ("uint8[]");
14477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
14577cb4d3eSLandon J. Fuller 		return ("uint16[]");
14677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
14777cb4d3eSLandon J. Fuller 		return ("uint32[]");
14877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
14977cb4d3eSLandon J. Fuller 		return ("uint64[]");
15077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
15177cb4d3eSLandon J. Fuller 		return ("int8[]");
15277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
15377cb4d3eSLandon J. Fuller 		return ("int16[]");
15477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
15577cb4d3eSLandon J. Fuller 		return ("int32[]");
15677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
15777cb4d3eSLandon J. Fuller 		return ("int64[]");
15877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
15977cb4d3eSLandon J. Fuller 		return ("char[]");
16077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
16177cb4d3eSLandon J. Fuller 		return ("string[]");
1626cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
1636cffadf0SLandon J. Fuller 		return ("bool[]");
16477cb4d3eSLandon J. Fuller 	}
16577cb4d3eSLandon J. Fuller 
16677cb4d3eSLandon J. Fuller 	/* Quiesce gcc4.2 */
16777cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
16877cb4d3eSLandon J. Fuller }
16977cb4d3eSLandon J. Fuller 
17077cb4d3eSLandon J. Fuller /**
17177cb4d3eSLandon J. Fuller  * Return true if @p type is a signed integer type, false otherwise.
17277cb4d3eSLandon J. Fuller  *
17377cb4d3eSLandon J. Fuller  * Will return false for all array types.
17477cb4d3eSLandon J. Fuller  *
17577cb4d3eSLandon J. Fuller  * @param type The type to query.
17677cb4d3eSLandon J. Fuller  */
17777cb4d3eSLandon J. Fuller bool
bhnd_nvram_is_signed_type(bhnd_nvram_type type)17877cb4d3eSLandon J. Fuller bhnd_nvram_is_signed_type(bhnd_nvram_type type)
17977cb4d3eSLandon J. Fuller {
18077cb4d3eSLandon J. Fuller 	switch (type) {
18177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
18277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
18377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
18477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
18577cb4d3eSLandon J. Fuller 		BHND_NV_ASSERT(bhnd_nvram_is_int_type(type), ("non-int type?"));
18677cb4d3eSLandon J. Fuller 		return (true);
18777cb4d3eSLandon J. Fuller 
18877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
18977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
19077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
19177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
19277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
19377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
1946cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
1956cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
1966cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
19777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
19877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
19977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
20077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
20177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
20277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
20377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
20477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
20577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
20677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
2076cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
20877cb4d3eSLandon J. Fuller 		return (false);
20977cb4d3eSLandon J. Fuller 	}
21077cb4d3eSLandon J. Fuller 
21177cb4d3eSLandon J. Fuller 	/* Quiesce gcc4.2 */
21277cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
21377cb4d3eSLandon J. Fuller }
21477cb4d3eSLandon J. Fuller 
21577cb4d3eSLandon J. Fuller /**
21677cb4d3eSLandon J. Fuller  * Return true if @p type is an unsigned integer type, false otherwise.
21777cb4d3eSLandon J. Fuller  *
21877cb4d3eSLandon J. Fuller  * @param type The type to query.
21977cb4d3eSLandon J. Fuller  *
22077cb4d3eSLandon J. Fuller  * @return Will return false for all array types.
22177cb4d3eSLandon J. Fuller  * @return Will return true for BHND_NVRAM_TYPE_CHAR.
22277cb4d3eSLandon J. Fuller  */
22377cb4d3eSLandon J. Fuller bool
bhnd_nvram_is_unsigned_type(bhnd_nvram_type type)22477cb4d3eSLandon J. Fuller bhnd_nvram_is_unsigned_type(bhnd_nvram_type type)
22577cb4d3eSLandon J. Fuller {
22677cb4d3eSLandon J. Fuller 	/* If an integer type, must be either signed or unsigned */
22777cb4d3eSLandon J. Fuller 	if (!bhnd_nvram_is_int_type(type))
22877cb4d3eSLandon J. Fuller 		return (false);
22977cb4d3eSLandon J. Fuller 
23077cb4d3eSLandon J. Fuller 	return (!bhnd_nvram_is_signed_type(type));
23177cb4d3eSLandon J. Fuller }
23277cb4d3eSLandon J. Fuller 
23377cb4d3eSLandon J. Fuller /**
23477cb4d3eSLandon J. Fuller  * Return true if bhnd_nvram_is_signed_type() or bhnd_nvram_is_unsigned_type()
23577cb4d3eSLandon J. Fuller  * returns true for @p type.
23677cb4d3eSLandon J. Fuller  *
23777cb4d3eSLandon J. Fuller  * @param type The type to query.
23877cb4d3eSLandon J. Fuller  */
23977cb4d3eSLandon J. Fuller bool
bhnd_nvram_is_int_type(bhnd_nvram_type type)24077cb4d3eSLandon J. Fuller bhnd_nvram_is_int_type(bhnd_nvram_type type)
24177cb4d3eSLandon J. Fuller {
24277cb4d3eSLandon J. Fuller 	switch (type) {
24377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
24477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
24577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
24677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
24777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
24877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
24977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
25077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
25177cb4d3eSLandon J. Fuller 		return (true);
25277cb4d3eSLandon J. Fuller 
25377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
25477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
2556cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
2566cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
2576cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
25877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
25977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
26077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
26177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
26277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
26377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
26477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
26577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
26677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
26777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
2686cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
26977cb4d3eSLandon J. Fuller 		return (false);
27077cb4d3eSLandon J. Fuller 	}
27177cb4d3eSLandon J. Fuller 
27277cb4d3eSLandon J. Fuller 	/* Quiesce gcc4.2 */
27377cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
27477cb4d3eSLandon J. Fuller }
27577cb4d3eSLandon J. Fuller 
27677cb4d3eSLandon J. Fuller /**
27777cb4d3eSLandon J. Fuller  * Return true if @p type is an array type, false otherwise.
27877cb4d3eSLandon J. Fuller  *
27977cb4d3eSLandon J. Fuller  * @param type The type to query.
28077cb4d3eSLandon J. Fuller  */
28177cb4d3eSLandon J. Fuller bool
bhnd_nvram_is_array_type(bhnd_nvram_type type)28277cb4d3eSLandon J. Fuller bhnd_nvram_is_array_type(bhnd_nvram_type type)
28377cb4d3eSLandon J. Fuller {
28477cb4d3eSLandon J. Fuller 	switch (type) {
28577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
28677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
28777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
28877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
28977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
29077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
29177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
29277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
29377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
29477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
2956cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
2966cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
2976cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
29877cb4d3eSLandon J. Fuller 		return (false);
29977cb4d3eSLandon J. Fuller 
30077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
30177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
30277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
30377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
30477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
30577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
30677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
30777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
30877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
30977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
3106cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
31177cb4d3eSLandon J. Fuller 		return (true);
31277cb4d3eSLandon J. Fuller 	}
31377cb4d3eSLandon J. Fuller 
31477cb4d3eSLandon J. Fuller 	/* Quiesce gcc4.2 */
31577cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
31677cb4d3eSLandon J. Fuller }
31777cb4d3eSLandon J. Fuller 
31877cb4d3eSLandon J. Fuller /**
31977cb4d3eSLandon J. Fuller  * If @p type is an array type, return the base element type. Otherwise,
32077cb4d3eSLandon J. Fuller  * returns @p type.
32177cb4d3eSLandon J. Fuller  *
32277cb4d3eSLandon J. Fuller  * @param type The type to query.
32377cb4d3eSLandon J. Fuller  */
32477cb4d3eSLandon J. Fuller bhnd_nvram_type
bhnd_nvram_base_type(bhnd_nvram_type type)32577cb4d3eSLandon J. Fuller bhnd_nvram_base_type(bhnd_nvram_type type)
32677cb4d3eSLandon J. Fuller {
32777cb4d3eSLandon J. Fuller 	switch (type) {
32877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
32977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
33077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
33177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
33277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
33377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
33477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
33577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
33677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
33777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
3386cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
3396cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
3406cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
34177cb4d3eSLandon J. Fuller 		return (type);
34277cb4d3eSLandon J. Fuller 
34377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:	return (BHND_NVRAM_TYPE_UINT8);
34477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:	return (BHND_NVRAM_TYPE_UINT16);
34577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:	return (BHND_NVRAM_TYPE_UINT32);
34677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:	return (BHND_NVRAM_TYPE_UINT64);
34777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:	return (BHND_NVRAM_TYPE_INT8);
34877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:	return (BHND_NVRAM_TYPE_INT16);
34977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:	return (BHND_NVRAM_TYPE_INT32);
35077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:	return (BHND_NVRAM_TYPE_INT64);
35177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:	return (BHND_NVRAM_TYPE_CHAR);
35277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:	return (BHND_NVRAM_TYPE_STRING);
3536cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:	return (BHND_NVRAM_TYPE_BOOL);
3546cffadf0SLandon J. Fuller 	}
3556cffadf0SLandon J. Fuller 
3566cffadf0SLandon J. Fuller 	/* Quiesce gcc4.2 */
3576cffadf0SLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
3586cffadf0SLandon J. Fuller }
3596cffadf0SLandon J. Fuller 
3606cffadf0SLandon J. Fuller /**
3616cffadf0SLandon J. Fuller  * Return the raw data type used to represent values of @p type, or return
3626cffadf0SLandon J. Fuller  * @p type is @p type is not a complex type.
3636cffadf0SLandon J. Fuller  *
3646cffadf0SLandon J. Fuller  * @param type The type to query.
3656cffadf0SLandon J. Fuller  */
3666cffadf0SLandon J. Fuller bhnd_nvram_type
bhnd_nvram_raw_type(bhnd_nvram_type type)3676cffadf0SLandon J. Fuller bhnd_nvram_raw_type(bhnd_nvram_type type)
3686cffadf0SLandon J. Fuller {
3696cffadf0SLandon J. Fuller 	switch (type) {
3706cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
3716cffadf0SLandon J. Fuller 		return (BHND_NVRAM_TYPE_UINT8);
3726cffadf0SLandon J. Fuller 
3736cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
3746cffadf0SLandon J. Fuller 		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
3756cffadf0SLandon J. Fuller 
3766cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL: {
3776cffadf0SLandon J. Fuller 		_Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
3786cffadf0SLandon J. Fuller 		    "bhnd_nvram_bool_t must be uint8-representable");
3796cffadf0SLandon J. Fuller 		return (BHND_NVRAM_TYPE_UINT8);
3806cffadf0SLandon J. Fuller 	}
3816cffadf0SLandon J. Fuller 
3826cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
3836cffadf0SLandon J. Fuller 		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
3846cffadf0SLandon J. Fuller 
3856cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
3866cffadf0SLandon J. Fuller 		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
3876cffadf0SLandon J. Fuller 
3886cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
3896cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
3906cffadf0SLandon J. Fuller 		return (BHND_NVRAM_TYPE_UINT8_ARRAY);
3916cffadf0SLandon J. Fuller 
3926cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
3936cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
3946cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
3956cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
3966cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
3976cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
3986cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
3996cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
4006cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
4016cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
4026cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
4036cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
4046cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
4056cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
4066cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
4076cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
4086cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
4096cffadf0SLandon J. Fuller 		return (type);
41077cb4d3eSLandon J. Fuller 	}
41177cb4d3eSLandon J. Fuller 
41277cb4d3eSLandon J. Fuller 	/* Quiesce gcc4.2 */
41377cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
41477cb4d3eSLandon J. Fuller }
41577cb4d3eSLandon J. Fuller 
41677cb4d3eSLandon J. Fuller /**
4179be0790dSLandon J. Fuller  * Return the size, in bytes, of a single element of @p type, or 0
4189be0790dSLandon J. Fuller  * if @p type is a variable-width type.
41977cb4d3eSLandon J. Fuller  *
4209be0790dSLandon J. Fuller  * @param type	The type to query.
42177cb4d3eSLandon J. Fuller  */
42277cb4d3eSLandon J. Fuller size_t
bhnd_nvram_type_width(bhnd_nvram_type type)4239be0790dSLandon J. Fuller bhnd_nvram_type_width(bhnd_nvram_type type)
42477cb4d3eSLandon J. Fuller {
42577cb4d3eSLandon J. Fuller 	switch (type) {
4269be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
4279be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
4286cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
42977cb4d3eSLandon J. Fuller 		return (0);
43077cb4d3eSLandon J. Fuller 
4316cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
4326cffadf0SLandon J. Fuller 		return (0);
4336cffadf0SLandon J. Fuller 
4346cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
4356cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY:
4366cffadf0SLandon J. Fuller 		return (sizeof(bhnd_nvram_bool_t));
4376cffadf0SLandon J. Fuller 
43877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
4399be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
4409be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
4419be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
4429be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
4439be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
44477cb4d3eSLandon J. Fuller 		return (sizeof(uint8_t));
44577cb4d3eSLandon J. Fuller 
44677cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
4479be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
4489be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
4499be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
45077cb4d3eSLandon J. Fuller 		return (sizeof(uint16_t));
45177cb4d3eSLandon J. Fuller 
45277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
4539be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
4549be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
4559be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
45677cb4d3eSLandon J. Fuller 		return (sizeof(uint32_t));
45777cb4d3eSLandon J. Fuller 
45877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
4599be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
46077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
4619be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
46277cb4d3eSLandon J. Fuller 		return (sizeof(uint64_t));
46377cb4d3eSLandon J. Fuller 	}
46477cb4d3eSLandon J. Fuller 
46577cb4d3eSLandon J. Fuller 	/* Quiesce gcc4.2 */
46677cb4d3eSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
46777cb4d3eSLandon J. Fuller }
46877cb4d3eSLandon J. Fuller 
46977cb4d3eSLandon J. Fuller /**
4709be0790dSLandon J. Fuller  * Return the native host alignment for values of @p type.
47177cb4d3eSLandon J. Fuller  *
4729be0790dSLandon J. Fuller  * @param type The type to query.
4739be0790dSLandon J. Fuller  */
4749be0790dSLandon J. Fuller size_t
bhnd_nvram_type_host_align(bhnd_nvram_type type)4759be0790dSLandon J. Fuller bhnd_nvram_type_host_align(bhnd_nvram_type type)
4769be0790dSLandon J. Fuller {
4779be0790dSLandon J. Fuller 	switch (type) {
4789be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
4799be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR_ARRAY:
4806cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_DATA:
4819be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING:
4829be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_STRING_ARRAY:
4839be0790dSLandon J. Fuller 		return (_Alignof(uint8_t));
4846cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL:
4856cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_BOOL_ARRAY: {
4866cffadf0SLandon J. Fuller 		_Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
4876cffadf0SLandon J. Fuller 		    "bhnd_nvram_bool_t must be uint8-representable");
4886cffadf0SLandon J. Fuller 		return (_Alignof(uint8_t));
4896cffadf0SLandon J. Fuller 	}
4906cffadf0SLandon J. Fuller 	case BHND_NVRAM_TYPE_NULL:
4916cffadf0SLandon J. Fuller 		return (1);
4929be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
4939be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8_ARRAY:
4949be0790dSLandon J. Fuller 		return (_Alignof(uint8_t));
4959be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
4969be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16_ARRAY:
4979be0790dSLandon J. Fuller 		return (_Alignof(uint16_t));
4989be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
4999be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32_ARRAY:
5009be0790dSLandon J. Fuller 		return (_Alignof(uint32_t));
5019be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
5029be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64_ARRAY:
5039be0790dSLandon J. Fuller 		return (_Alignof(uint64_t));
5049be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
5059be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8_ARRAY:
5069be0790dSLandon J. Fuller 		return (_Alignof(int8_t));
5079be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
5089be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16_ARRAY:
5099be0790dSLandon J. Fuller 		return (_Alignof(int16_t));
5109be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
5119be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32_ARRAY:
5129be0790dSLandon J. Fuller 		return (_Alignof(int32_t));
5139be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
5149be0790dSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64_ARRAY:
5159be0790dSLandon J. Fuller 		return (_Alignof(int64_t));
5169be0790dSLandon J. Fuller 	}
5179be0790dSLandon J. Fuller 
5189be0790dSLandon J. Fuller 	/* Quiesce gcc4.2 */
5199be0790dSLandon J. Fuller 	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
5209be0790dSLandon J. Fuller }
5219be0790dSLandon J. Fuller 
5229be0790dSLandon J. Fuller /**
523*05ed3f90SLandon J. Fuller  * Iterate over all strings in the @p inp string array (see
524*05ed3f90SLandon J. Fuller  * BHND_NVRAM_TYPE_STRING_ARRAY).
5259be0790dSLandon J. Fuller  *
5269be0790dSLandon J. Fuller  * @param		inp	The string array to be iterated. This must be a
5279be0790dSLandon J. Fuller  *				buffer of one or more NUL-terminated strings.
52877cb4d3eSLandon J. Fuller  * @param		ilen	The size, in bytes, of @p inp, including any
52977cb4d3eSLandon J. Fuller  *				terminating NUL character(s).
5309be0790dSLandon J. Fuller  * @param		prev	The pointer previously returned by
53177cb4d3eSLandon J. Fuller  *				bhnd_nvram_string_array_next(), or NULL to begin
53277cb4d3eSLandon J. Fuller  *				iteration.
5339be0790dSLandon J. Fuller * @param[in,out]	olen	If @p prev is non-NULL, @p olen must be a
5349be0790dSLandon J. Fuller  *				pointer to the length previously returned by
5359be0790dSLandon J. Fuller  *				bhnd_nvram_string_array_next(). On success, will
5369be0790dSLandon J. Fuller  *				be set to the next element's length, in bytes.
53777cb4d3eSLandon J. Fuller  *
53877cb4d3eSLandon J. Fuller  * @retval non-NULL	A reference to the next NUL-terminated string
53977cb4d3eSLandon J. Fuller  * @retval NULL		If the end of the string array is reached.
540*05ed3f90SLandon J. Fuller  *
541*05ed3f90SLandon J. Fuller  * @see BHND_NVRAM_TYPE_STRING_ARRAY
54277cb4d3eSLandon J. Fuller  */
54377cb4d3eSLandon J. Fuller const char *
bhnd_nvram_string_array_next(const char * inp,size_t ilen,const char * prev,size_t * olen)5449be0790dSLandon J. Fuller bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev,
5459be0790dSLandon J. Fuller     size_t *olen)
54677cb4d3eSLandon J. Fuller {
5479be0790dSLandon J. Fuller 	return (bhnd_nvram_value_array_next(inp, ilen,
5489be0790dSLandon J. Fuller 	    BHND_NVRAM_TYPE_STRING_ARRAY, prev, olen));
54977cb4d3eSLandon J. Fuller }
55077cb4d3eSLandon J. Fuller 
55177cb4d3eSLandon J. Fuller /* used by bhnd_nvram_find_vardefn() */
55277cb4d3eSLandon J. Fuller static int
bhnd_nvram_find_vardefn_compare(const void * key,const void * rhs)55377cb4d3eSLandon J. Fuller bhnd_nvram_find_vardefn_compare(const void *key, const void *rhs)
55477cb4d3eSLandon J. Fuller {
55577cb4d3eSLandon J. Fuller 	const struct bhnd_nvram_vardefn *r = rhs;
55677cb4d3eSLandon J. Fuller 
55777cb4d3eSLandon J. Fuller 	return (strcmp((const char *)key, r->name));
55877cb4d3eSLandon J. Fuller }
55977cb4d3eSLandon J. Fuller 
56077cb4d3eSLandon J. Fuller /**
56177cb4d3eSLandon J. Fuller  * Find and return the variable definition for @p varname, if any.
56277cb4d3eSLandon J. Fuller  *
56377cb4d3eSLandon J. Fuller  * @param varname variable name
56477cb4d3eSLandon J. Fuller  *
56577cb4d3eSLandon J. Fuller  * @retval bhnd_nvram_vardefn If a valid definition for @p varname is found.
56677cb4d3eSLandon J. Fuller  * @retval NULL If no definition for @p varname is found.
56777cb4d3eSLandon J. Fuller  */
56877cb4d3eSLandon J. Fuller const struct bhnd_nvram_vardefn *
bhnd_nvram_find_vardefn(const char * varname)56977cb4d3eSLandon J. Fuller bhnd_nvram_find_vardefn(const char *varname)
57077cb4d3eSLandon J. Fuller {
57177cb4d3eSLandon J. Fuller 	return (bsearch(varname, bhnd_nvram_vardefns, bhnd_nvram_num_vardefns,
57277cb4d3eSLandon J. Fuller 	    sizeof(bhnd_nvram_vardefns[0]), bhnd_nvram_find_vardefn_compare));
57377cb4d3eSLandon J. Fuller }
57477cb4d3eSLandon J. Fuller 
57577cb4d3eSLandon J. Fuller /**
57677cb4d3eSLandon J. Fuller  * Return the variable ID for a variable definition.
57777cb4d3eSLandon J. Fuller  *
57877cb4d3eSLandon J. Fuller  * @param defn Variable definition previously returned by
57977cb4d3eSLandon J. Fuller  * bhnd_nvram_find_vardefn() or bhnd_nvram_get_vardefn().
58077cb4d3eSLandon J. Fuller  */
58177cb4d3eSLandon J. Fuller size_t
bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn * defn)58277cb4d3eSLandon J. Fuller bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn *defn)
58377cb4d3eSLandon J. Fuller {
58477cb4d3eSLandon J. Fuller 	BHND_NV_ASSERT(
58577cb4d3eSLandon J. Fuller 	    defn >= bhnd_nvram_vardefns &&
58677cb4d3eSLandon J. Fuller 	    defn <= &bhnd_nvram_vardefns[bhnd_nvram_num_vardefns-1],
58777cb4d3eSLandon J. Fuller 	    ("invalid variable definition pointer %p", defn));
58877cb4d3eSLandon J. Fuller 
58977cb4d3eSLandon J. Fuller 	return (defn - bhnd_nvram_vardefns);
59077cb4d3eSLandon J. Fuller }
59177cb4d3eSLandon J. Fuller 
59277cb4d3eSLandon J. Fuller /**
59377cb4d3eSLandon J. Fuller  * Return the variable definition with the given @p id, or NULL
59477cb4d3eSLandon J. Fuller  * if no such variable ID is defined.
59577cb4d3eSLandon J. Fuller  *
59677cb4d3eSLandon J. Fuller  * @param id variable ID.
59777cb4d3eSLandon J. Fuller  *
59877cb4d3eSLandon J. Fuller  * @retval bhnd_nvram_vardefn If a valid definition for @p id is found.
59977cb4d3eSLandon J. Fuller  * @retval NULL If no definition for @p id is found.
60077cb4d3eSLandon J. Fuller  */
60177cb4d3eSLandon J. Fuller const struct bhnd_nvram_vardefn *
bhnd_nvram_get_vardefn(size_t id)60277cb4d3eSLandon J. Fuller bhnd_nvram_get_vardefn(size_t id)
60377cb4d3eSLandon J. Fuller {
60477cb4d3eSLandon J. Fuller 	if (id >= bhnd_nvram_num_vardefns)
60577cb4d3eSLandon J. Fuller 		return (NULL);
60677cb4d3eSLandon J. Fuller 
60777cb4d3eSLandon J. Fuller 	return (&bhnd_nvram_vardefns[id]);
60877cb4d3eSLandon J. Fuller }
60977cb4d3eSLandon J. Fuller 
61077cb4d3eSLandon J. Fuller /**
61177cb4d3eSLandon J. Fuller  * Validate an NVRAM variable name.
61277cb4d3eSLandon J. Fuller  *
61377cb4d3eSLandon J. Fuller  * Scans for special characters (path delimiters, value delimiters, path
61477cb4d3eSLandon J. Fuller  * alias prefixes), returning false if the given name cannot be used
61577cb4d3eSLandon J. Fuller  * as a relative NVRAM key.
61677cb4d3eSLandon J. Fuller  *
61777cb4d3eSLandon J. Fuller  * @param name A relative NVRAM variable name to validate.
61877cb4d3eSLandon J. Fuller  *
61977cb4d3eSLandon J. Fuller  * @retval true If @p name is a valid relative NVRAM key.
62077cb4d3eSLandon J. Fuller  * @retval false If @p name should not be used as a relative NVRAM key.
62177cb4d3eSLandon J. Fuller  */
62277cb4d3eSLandon J. Fuller bool
bhnd_nvram_validate_name(const char * name)62319be09f3SLandon J. Fuller bhnd_nvram_validate_name(const char *name)
62477cb4d3eSLandon J. Fuller {
62519be09f3SLandon J. Fuller 	/* Reject path-prefixed variable names */
62619be09f3SLandon J. Fuller 	if (bhnd_nvram_trim_path_name(name) != name)
62777cb4d3eSLandon J. Fuller 		return (false);
62877cb4d3eSLandon J. Fuller 
62919be09f3SLandon J. Fuller 	/* Reject device path alias declarations (devpath[1-9][0-9]*.*\0) */
63019be09f3SLandon J. Fuller 	if (strncmp(name, "devpath", strlen("devpath")) == 0) {
63119be09f3SLandon J. Fuller 		const char	*p;
63219be09f3SLandon J. Fuller 		char		*endp;
63319be09f3SLandon J. Fuller 
63419be09f3SLandon J. Fuller 		/* Check for trailing [1-9][0-9]* */
63519be09f3SLandon J. Fuller 		p = name + strlen("devpath");
63619be09f3SLandon J. Fuller 		strtoul(p, &endp, 10);
63719be09f3SLandon J. Fuller 		if (endp != p)
63877cb4d3eSLandon J. Fuller 			return (false);
63977cb4d3eSLandon J. Fuller 	}
64077cb4d3eSLandon J. Fuller 
64119be09f3SLandon J. Fuller 	/* Scan for [^A-Za-z_0-9] */
64219be09f3SLandon J. Fuller 	for (const char *p = name; *p != '\0'; p++) {
64377cb4d3eSLandon J. Fuller 		switch (*p) {
64419be09f3SLandon J. Fuller 		/* [0-9_] */
64519be09f3SLandon J. Fuller 		case '0': case '1': case '2': case '3': case '4':
64619be09f3SLandon J. Fuller 		case '5': case '6': case '7': case '8': case '9':
64719be09f3SLandon J. Fuller 		case '_':
64819be09f3SLandon J. Fuller 			break;
64977cb4d3eSLandon J. Fuller 
65019be09f3SLandon J. Fuller 		/* [A-Za-z] */
65177cb4d3eSLandon J. Fuller 		default:
65219be09f3SLandon J. Fuller 			if (!bhnd_nv_isalpha(*p))
65377cb4d3eSLandon J. Fuller 				return (false);
65419be09f3SLandon J. Fuller 			break;
65577cb4d3eSLandon J. Fuller 		}
65677cb4d3eSLandon J. Fuller 	}
65777cb4d3eSLandon J. Fuller 
65877cb4d3eSLandon J. Fuller 	return (true);
65977cb4d3eSLandon J. Fuller }
66077cb4d3eSLandon J. Fuller 
66177cb4d3eSLandon J. Fuller /**
66277cb4d3eSLandon J. Fuller  * Parses the string in the optionally NUL-terminated @p str to as an integer
66377cb4d3eSLandon J. Fuller  * value of @p otype, accepting any integer format supported by the standard
66477cb4d3eSLandon J. Fuller  * strtoul().
66577cb4d3eSLandon J. Fuller  *
66677cb4d3eSLandon J. Fuller  * - Any leading whitespace in @p str -- as defined by the equivalent of
66777cb4d3eSLandon J. Fuller  *   calling isspace_l() with an ASCII locale -- will be ignored.
66877cb4d3eSLandon J. Fuller  * - A @p str may be prefixed with a single optional '+' or '-' sign denoting
66977cb4d3eSLandon J. Fuller  *   signedness.
67077cb4d3eSLandon J. Fuller  * - A hexadecimal @p str may include an '0x' or '0X' prefix, denoting that a
67177cb4d3eSLandon J. Fuller  *   base 16 integer follows.
67277cb4d3eSLandon J. Fuller  * - An octal @p str may include a '0' prefix, denoting that an octal integer
67377cb4d3eSLandon J. Fuller  *   follows.
67477cb4d3eSLandon J. Fuller  *
67577cb4d3eSLandon J. Fuller  * If a @p base of 0 is specified, the base will be determined according
67677cb4d3eSLandon J. Fuller  * to the string's initial prefix, as per strtoul()'s documented behavior.
67777cb4d3eSLandon J. Fuller  *
67877cb4d3eSLandon J. Fuller  * When parsing a base 16 integer to a signed representation, if no explicit
67977cb4d3eSLandon J. Fuller  * sign prefix is given, the string will be parsed as the raw two's complement
68077cb4d3eSLandon J. Fuller  * representation of the signed integer value.
68177cb4d3eSLandon J. Fuller  *
68277cb4d3eSLandon J. Fuller  * @param		str	The string to be parsed.
68377cb4d3eSLandon J. Fuller  * @param		maxlen	The maximum number of bytes to be read in
68477cb4d3eSLandon J. Fuller  *				@p str.
68577cb4d3eSLandon J. Fuller  * @param		base	The input string's base (2-36), or 0.
68677cb4d3eSLandon J. Fuller  * @param[out]		nbytes	On success or failure, will be set to the total
68777cb4d3eSLandon J. Fuller  *				number of parsed bytes. If the total number of
68877cb4d3eSLandon J. Fuller  *				bytes is not desired, a NULL pointer may be
68977cb4d3eSLandon J. Fuller  *				provided.
69077cb4d3eSLandon J. Fuller  * @param[out]		outp	On success, the parsed integer value will be
69177cb4d3eSLandon J. Fuller  *				written to @p outp. This argment may be NULL if
69277cb4d3eSLandon J. Fuller  *				the value is not desired.
69377cb4d3eSLandon J. Fuller  * @param[in,out]	olen	The capacity of @p outp. On success, will be set
69477cb4d3eSLandon J. Fuller  *				to the actual size of the requested value.
69577cb4d3eSLandon J. Fuller  * @param		otype	The integer type to be parsed.
69677cb4d3eSLandon J. Fuller  *
69777cb4d3eSLandon J. Fuller  * @retval 0		success
69877cb4d3eSLandon J. Fuller  * @retval EINVAL	if an invalid @p base is specified.
69977cb4d3eSLandon J. Fuller  * @retval EINVAL	if an unsupported (or non-integer) @p otype is
70077cb4d3eSLandon J. Fuller  *			specified.
70177cb4d3eSLandon J. Fuller  * @retval ENOMEM	If @p outp is non-NULL and a buffer of @p olen is too
70277cb4d3eSLandon J. Fuller  *			small to hold the requested value.
70377cb4d3eSLandon J. Fuller  * @retval EFTYPE	if @p str cannot be parsed as an integer of @p base.
70477cb4d3eSLandon J. Fuller  * @retval ERANGE	If the integer parsed from @p str is too large to be
70577cb4d3eSLandon J. Fuller  *			represented as a value of @p otype.
70677cb4d3eSLandon J. Fuller  */
70777cb4d3eSLandon J. Fuller int
bhnd_nvram_parse_int(const char * str,size_t maxlen,u_int base,size_t * nbytes,void * outp,size_t * olen,bhnd_nvram_type otype)70877cb4d3eSLandon J. Fuller bhnd_nvram_parse_int(const char *str, size_t maxlen,  u_int base,
70977cb4d3eSLandon J. Fuller     size_t *nbytes, void *outp, size_t *olen, bhnd_nvram_type otype)
71077cb4d3eSLandon J. Fuller {
71177cb4d3eSLandon J. Fuller 	uint64_t	value;
71277cb4d3eSLandon J. Fuller 	uint64_t	carry_max, value_max;
71377cb4d3eSLandon J. Fuller 	uint64_t	type_max;
71477cb4d3eSLandon J. Fuller 	size_t		limit, local_nbytes;
71577cb4d3eSLandon J. Fuller 	size_t		ndigits;
71677cb4d3eSLandon J. Fuller 	bool		negative, sign, twos_compl;
71777cb4d3eSLandon J. Fuller 
71877cb4d3eSLandon J. Fuller 	/* Must be an integer type */
71977cb4d3eSLandon J. Fuller 	if (!bhnd_nvram_is_int_type(otype))
72077cb4d3eSLandon J. Fuller 		return (EINVAL);
72177cb4d3eSLandon J. Fuller 
72277cb4d3eSLandon J. Fuller 	/* Determine output byte limit */
72377cb4d3eSLandon J. Fuller 	if (outp != NULL)
72477cb4d3eSLandon J. Fuller 		limit = *olen;
72577cb4d3eSLandon J. Fuller 	else
72677cb4d3eSLandon J. Fuller 		limit = 0;
72777cb4d3eSLandon J. Fuller 
72877cb4d3eSLandon J. Fuller 	/* We always need a byte count. If the caller provides a NULL nbytes,
72977cb4d3eSLandon J. Fuller 	 * track our position in a stack variable */
73077cb4d3eSLandon J. Fuller 	if (nbytes == NULL)
73177cb4d3eSLandon J. Fuller 		nbytes = &local_nbytes;
73277cb4d3eSLandon J. Fuller 
73377cb4d3eSLandon J. Fuller 	value = 0;
73477cb4d3eSLandon J. Fuller 	ndigits = 0;
73577cb4d3eSLandon J. Fuller 	*nbytes = 0;
73677cb4d3eSLandon J. Fuller 	negative = false;
73777cb4d3eSLandon J. Fuller 	sign = false;
73877cb4d3eSLandon J. Fuller 
73977cb4d3eSLandon J. Fuller 	/* Validate the specified base */
74077cb4d3eSLandon J. Fuller 	if (base != 0 && !(base >= 2 && base <= 36))
74177cb4d3eSLandon J. Fuller 		return (EINVAL);
74277cb4d3eSLandon J. Fuller 
74377cb4d3eSLandon J. Fuller 	/* Skip any leading whitespace */
74477cb4d3eSLandon J. Fuller 	for (; *nbytes < maxlen; (*nbytes)++) {
74577cb4d3eSLandon J. Fuller 		if (!bhnd_nv_isspace(str[*nbytes]))
74677cb4d3eSLandon J. Fuller 			break;
74777cb4d3eSLandon J. Fuller 	}
74877cb4d3eSLandon J. Fuller 
74977cb4d3eSLandon J. Fuller 	/* Empty string? */
75077cb4d3eSLandon J. Fuller 	if (*nbytes == maxlen)
75177cb4d3eSLandon J. Fuller 		return (EFTYPE);
75277cb4d3eSLandon J. Fuller 
75377cb4d3eSLandon J. Fuller 	/* Parse and skip sign */
75477cb4d3eSLandon J. Fuller 	if (str[*nbytes] == '-') {
75577cb4d3eSLandon J. Fuller 		negative = true;
75677cb4d3eSLandon J. Fuller 		sign = true;
75777cb4d3eSLandon J. Fuller 		(*nbytes)++;
75877cb4d3eSLandon J. Fuller 	} else if (str[*nbytes] == '+') {
75977cb4d3eSLandon J. Fuller 		sign = true;
76077cb4d3eSLandon J. Fuller 		(*nbytes)++;
76177cb4d3eSLandon J. Fuller 	}
76277cb4d3eSLandon J. Fuller 
76377cb4d3eSLandon J. Fuller 	/* Truncated after sign character? */
76477cb4d3eSLandon J. Fuller 	if (*nbytes == maxlen)
76577cb4d3eSLandon J. Fuller 		return (EFTYPE);
76677cb4d3eSLandon J. Fuller 
76777cb4d3eSLandon J. Fuller 	/* Identify (or validate) hex base, skipping 0x/0X prefix */
76877cb4d3eSLandon J. Fuller 	if (base == 16 || base == 0) {
76977cb4d3eSLandon J. Fuller 		/* Check for (and skip) 0x/0X prefix */
77077cb4d3eSLandon J. Fuller 		if (maxlen - *nbytes >= 2 && str[*nbytes] == '0' &&
77177cb4d3eSLandon J. Fuller 		    (str[*nbytes+1] == 'x' || str[*nbytes+1] == 'X'))
77277cb4d3eSLandon J. Fuller 		{
77377cb4d3eSLandon J. Fuller 			base = 16;
77477cb4d3eSLandon J. Fuller 			(*nbytes) += 2;
77577cb4d3eSLandon J. Fuller 		}
77677cb4d3eSLandon J. Fuller 	}
77777cb4d3eSLandon J. Fuller 
77877cb4d3eSLandon J. Fuller 	/* Truncated after hex prefix? */
77977cb4d3eSLandon J. Fuller 	if (*nbytes == maxlen)
78077cb4d3eSLandon J. Fuller 		return (EFTYPE);
78177cb4d3eSLandon J. Fuller 
78277cb4d3eSLandon J. Fuller 	/* Differentiate decimal/octal by looking for a leading 0 */
78377cb4d3eSLandon J. Fuller 	if (base == 0) {
78477cb4d3eSLandon J. Fuller 		if (str[*nbytes] == '0') {
78577cb4d3eSLandon J. Fuller 			base = 8;
78677cb4d3eSLandon J. Fuller 		} else {
78777cb4d3eSLandon J. Fuller 			base = 10;
78877cb4d3eSLandon J. Fuller 		}
78977cb4d3eSLandon J. Fuller 	}
79077cb4d3eSLandon J. Fuller 
79177cb4d3eSLandon J. Fuller 	/* Only enable twos-compliment signed integer parsing enabled if the
79277cb4d3eSLandon J. Fuller 	 * input is base 16, and no explicit sign prefix was provided */
79377cb4d3eSLandon J. Fuller 	if (!sign && base == 16)
79477cb4d3eSLandon J. Fuller 		twos_compl = true;
79577cb4d3eSLandon J. Fuller 	else
79677cb4d3eSLandon J. Fuller 		twos_compl = false;
79777cb4d3eSLandon J. Fuller 
79877cb4d3eSLandon J. Fuller 	/* Determine the maximum value representable by the requested type */
79977cb4d3eSLandon J. Fuller 	switch (otype) {
80077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
80177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
80277cb4d3eSLandon J. Fuller 		type_max = (uint64_t)UINT8_MAX;
80377cb4d3eSLandon J. Fuller 		break;
80477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
80577cb4d3eSLandon J. Fuller 		type_max = (uint64_t)UINT16_MAX;
80677cb4d3eSLandon J. Fuller 		break;
80777cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
80877cb4d3eSLandon J. Fuller 		type_max = (uint64_t)UINT32_MAX;
80977cb4d3eSLandon J. Fuller 		break;
81077cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
81177cb4d3eSLandon J. Fuller 		type_max = (uint64_t)UINT64_MAX;
81277cb4d3eSLandon J. Fuller 		break;
81377cb4d3eSLandon J. Fuller 
81477cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
81577cb4d3eSLandon J. Fuller 		if (twos_compl)
81677cb4d3eSLandon J. Fuller 			type_max = (uint64_t)UINT8_MAX;
81777cb4d3eSLandon J. Fuller 		else if (negative)
81877cb4d3eSLandon J. Fuller 			type_max = -(uint64_t)INT8_MIN;
81977cb4d3eSLandon J. Fuller 		else
82077cb4d3eSLandon J. Fuller 			type_max = (uint64_t)INT8_MAX;
82177cb4d3eSLandon J. Fuller 		break;
82277cb4d3eSLandon J. Fuller 
82377cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
82477cb4d3eSLandon J. Fuller 		if (twos_compl)
82577cb4d3eSLandon J. Fuller 			type_max = (uint64_t)UINT16_MAX;
82677cb4d3eSLandon J. Fuller 		else if (negative)
82777cb4d3eSLandon J. Fuller 			type_max = -(uint64_t)INT16_MIN;
82877cb4d3eSLandon J. Fuller 		else
82977cb4d3eSLandon J. Fuller 			type_max = (uint64_t)INT16_MAX;
83077cb4d3eSLandon J. Fuller 		break;
83177cb4d3eSLandon J. Fuller 
83277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
83377cb4d3eSLandon J. Fuller 		if (twos_compl)
83477cb4d3eSLandon J. Fuller 			type_max = (uint64_t)UINT32_MAX;
83577cb4d3eSLandon J. Fuller 		else if (negative)
83677cb4d3eSLandon J. Fuller 			type_max = -(uint64_t)INT32_MIN;
83777cb4d3eSLandon J. Fuller 		else
83877cb4d3eSLandon J. Fuller 			type_max = (uint64_t)INT32_MAX;
83977cb4d3eSLandon J. Fuller 		break;
84077cb4d3eSLandon J. Fuller 
84177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
84277cb4d3eSLandon J. Fuller 		if (twos_compl)
84377cb4d3eSLandon J. Fuller 			type_max = (uint64_t)UINT64_MAX;
84477cb4d3eSLandon J. Fuller 		else if (negative)
84577cb4d3eSLandon J. Fuller 			type_max = -(uint64_t)INT64_MIN;
84677cb4d3eSLandon J. Fuller 		else
84777cb4d3eSLandon J. Fuller 			type_max = (uint64_t)INT64_MAX;
84877cb4d3eSLandon J. Fuller 		break;
84977cb4d3eSLandon J. Fuller 
85077cb4d3eSLandon J. Fuller 	default:
85177cb4d3eSLandon J. Fuller 		BHND_NV_LOG("unsupported integer type: %d\n", otype);
85277cb4d3eSLandon J. Fuller 		return (EINVAL);
85377cb4d3eSLandon J. Fuller 	}
85477cb4d3eSLandon J. Fuller 
85577cb4d3eSLandon J. Fuller 	/* The maximum value after which an additional carry would overflow */
85677cb4d3eSLandon J. Fuller 	value_max = type_max / (uint64_t)base;
85777cb4d3eSLandon J. Fuller 
85877cb4d3eSLandon J. Fuller 	/* The maximum carry value given a value equal to value_max */
85977cb4d3eSLandon J. Fuller 	carry_max = type_max % (uint64_t)base;
86077cb4d3eSLandon J. Fuller 
86177cb4d3eSLandon J. Fuller 	/* Consume input until we hit maxlen or a non-digit character */
86277cb4d3eSLandon J. Fuller 	for (; *nbytes < maxlen; (*nbytes)++) {
86377cb4d3eSLandon J. Fuller 		u_long	carry;
86477cb4d3eSLandon J. Fuller 		char	c;
86577cb4d3eSLandon J. Fuller 
86677cb4d3eSLandon J. Fuller 		/* Parse carry value */
86777cb4d3eSLandon J. Fuller 		c = str[*nbytes];
86877cb4d3eSLandon J. Fuller 		if (bhnd_nv_isdigit(c)) {
86977cb4d3eSLandon J. Fuller 			carry = c - '0';
87077cb4d3eSLandon J. Fuller 		} else if (bhnd_nv_isxdigit(c)) {
87177cb4d3eSLandon J. Fuller 			if (bhnd_nv_isupper(c))
87277cb4d3eSLandon J. Fuller 				carry = (c - 'A') + 10;
87377cb4d3eSLandon J. Fuller 			else
87477cb4d3eSLandon J. Fuller 				carry = (c - 'a') + 10;
87577cb4d3eSLandon J. Fuller 		} else {
87677cb4d3eSLandon J. Fuller 			/* Hit first non-digit character */
87777cb4d3eSLandon J. Fuller 			break;
87877cb4d3eSLandon J. Fuller 		}
87977cb4d3eSLandon J. Fuller 
88077cb4d3eSLandon J. Fuller 		/* If carry is outside the base, it's not a valid digit
88177cb4d3eSLandon J. Fuller 		 * in the current parse context; consider it a non-digit
88277cb4d3eSLandon J. Fuller 		 * character */
88377cb4d3eSLandon J. Fuller 		if (carry >= (uint64_t)base)
88477cb4d3eSLandon J. Fuller 			break;
88577cb4d3eSLandon J. Fuller 
88677cb4d3eSLandon J. Fuller 		/* Increment count of parsed digits */
88777cb4d3eSLandon J. Fuller 		ndigits++;
88877cb4d3eSLandon J. Fuller 
88977cb4d3eSLandon J. Fuller 		if (value > value_max) {
89077cb4d3eSLandon J. Fuller 			/* -Any- carry value would overflow */
89177cb4d3eSLandon J. Fuller 			return (ERANGE);
89277cb4d3eSLandon J. Fuller 		} else if (value == value_max && carry > carry_max) {
89377cb4d3eSLandon J. Fuller 			/* -This- carry value would overflow */
89477cb4d3eSLandon J. Fuller 			return (ERANGE);
89577cb4d3eSLandon J. Fuller 		}
89677cb4d3eSLandon J. Fuller 
89777cb4d3eSLandon J. Fuller 		value *= (uint64_t)base;
89877cb4d3eSLandon J. Fuller 		value += carry;
89977cb4d3eSLandon J. Fuller 	}
90077cb4d3eSLandon J. Fuller 
90177cb4d3eSLandon J. Fuller 	/* If we hit a non-digit character before parsing the first digit,
90277cb4d3eSLandon J. Fuller 	 * we hit an empty integer string. */
90377cb4d3eSLandon J. Fuller 	if (ndigits == 0)
90477cb4d3eSLandon J. Fuller 		return (EFTYPE);
90577cb4d3eSLandon J. Fuller 
90677cb4d3eSLandon J. Fuller 	if (negative)
90777cb4d3eSLandon J. Fuller 		value = -value;
90877cb4d3eSLandon J. Fuller 
90977cb4d3eSLandon J. Fuller 	/* Provide (and verify) required length */
9109be0790dSLandon J. Fuller 	*olen = bhnd_nvram_type_width(otype);
91177cb4d3eSLandon J. Fuller 	if (outp == NULL)
91277cb4d3eSLandon J. Fuller 		return (0);
91377cb4d3eSLandon J. Fuller 	else if (limit < *olen)
91477cb4d3eSLandon J. Fuller 		return (ENOMEM);
91577cb4d3eSLandon J. Fuller 
91677cb4d3eSLandon J. Fuller 	/* Provide result */
91777cb4d3eSLandon J. Fuller 	switch (otype) {
91877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_CHAR:
91977cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT8:
92077cb4d3eSLandon J. Fuller 		*(uint8_t *)outp = (uint8_t)value;
92177cb4d3eSLandon J. Fuller 		break;
92277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT16:
92377cb4d3eSLandon J. Fuller 		*(uint16_t *)outp = (uint16_t)value;
92477cb4d3eSLandon J. Fuller 		break;
92577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT32:
92677cb4d3eSLandon J. Fuller 		*(uint32_t *)outp = (uint32_t)value;
92777cb4d3eSLandon J. Fuller 		break;
92877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_UINT64:
92977cb4d3eSLandon J. Fuller 		*(uint64_t *)outp = (uint64_t)value;
93077cb4d3eSLandon J. Fuller 		break;
93177cb4d3eSLandon J. Fuller 
93277cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT8:
93377cb4d3eSLandon J. Fuller 		*(int8_t *)outp = (int8_t)(int64_t)value;
93477cb4d3eSLandon J. Fuller 		break;
93577cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT16:
93677cb4d3eSLandon J. Fuller 		*(int16_t *)outp = (int16_t)(int64_t)value;
93777cb4d3eSLandon J. Fuller 		break;
93877cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT32:
93977cb4d3eSLandon J. Fuller 		*(int32_t *)outp = (int32_t)(int64_t)value;
94077cb4d3eSLandon J. Fuller 		break;
94177cb4d3eSLandon J. Fuller 	case BHND_NVRAM_TYPE_INT64:
94277cb4d3eSLandon J. Fuller 		*(int64_t *)outp = (int64_t)value;
94377cb4d3eSLandon J. Fuller 		break;
94477cb4d3eSLandon J. Fuller 	default:
94577cb4d3eSLandon J. Fuller 		/* unreachable */
94677cb4d3eSLandon J. Fuller 		BHND_NV_PANIC("unhandled type %d\n", otype);
94777cb4d3eSLandon J. Fuller 	}
94877cb4d3eSLandon J. Fuller 
94977cb4d3eSLandon J. Fuller 	return (0);
95077cb4d3eSLandon J. Fuller }
95177cb4d3eSLandon J. Fuller 
95277cb4d3eSLandon J. Fuller /**
95319be09f3SLandon J. Fuller  * Trim leading path (pci/1/1) or path alias (0:) prefix from @p name, if any,
95419be09f3SLandon J. Fuller  * returning a pointer to the start of the relative variable name.
95519be09f3SLandon J. Fuller  *
95619be09f3SLandon J. Fuller  * @par Examples
95719be09f3SLandon J. Fuller  *
95819be09f3SLandon J. Fuller  * - "/foo"		-> "foo"
95919be09f3SLandon J. Fuller  * - "dev/pci/foo"	-> "foo"
96019be09f3SLandon J. Fuller  * - "0:foo"		-> "foo"
96119be09f3SLandon J. Fuller  * - "foo"		-> "foo"
96219be09f3SLandon J. Fuller  *
96319be09f3SLandon J. Fuller  * @param name The string to be trimmed.
96419be09f3SLandon J. Fuller  *
96519be09f3SLandon J. Fuller  * @return A pointer to the start of the relative variable name in @p name.
96619be09f3SLandon J. Fuller  */
96719be09f3SLandon J. Fuller const char *
bhnd_nvram_trim_path_name(const char * name)96819be09f3SLandon J. Fuller bhnd_nvram_trim_path_name(const char *name)
96919be09f3SLandon J. Fuller {
97019be09f3SLandon J. Fuller 	char *endp;
97119be09f3SLandon J. Fuller 
97219be09f3SLandon J. Fuller 	/* path alias prefix? (0:varname) */
97319be09f3SLandon J. Fuller 	if (bhnd_nv_isdigit(*name)) {
97419be09f3SLandon J. Fuller 		/* Parse '0...:' alias prefix, if it exists */
97519be09f3SLandon J. Fuller 		strtoul(name, &endp, 10);
97619be09f3SLandon J. Fuller 		if (endp != name && *endp == ':') {
97719be09f3SLandon J. Fuller 			/* Variable name follows 0: prefix */
97819be09f3SLandon J. Fuller 			return (endp+1);
97919be09f3SLandon J. Fuller 		}
98019be09f3SLandon J. Fuller 	}
98119be09f3SLandon J. Fuller 
98219be09f3SLandon J. Fuller 	/* device path prefix? (pci/1/1/varname) */
98319be09f3SLandon J. Fuller 	if ((endp = strrchr(name, '/')) != NULL) {
98419be09f3SLandon J. Fuller 		/* Variable name follows the final path separator '/' */
98519be09f3SLandon J. Fuller 		return (endp+1);
98619be09f3SLandon J. Fuller 	}
98719be09f3SLandon J. Fuller 
98819be09f3SLandon J. Fuller 	/* variable name is not prefixed */
98919be09f3SLandon J. Fuller 	return (name);
99019be09f3SLandon J. Fuller }
99119be09f3SLandon J. Fuller 
99219be09f3SLandon J. Fuller /**
99377cb4d3eSLandon J. Fuller  * Parse a 'name=value' string.
99477cb4d3eSLandon J. Fuller  *
99577cb4d3eSLandon J. Fuller  * @param env The string to be parsed.
99677cb4d3eSLandon J. Fuller  * @param env_len The length of @p envp.
99777cb4d3eSLandon J. Fuller  * @param delim The delimiter used in @p envp. This will generally be '='.
99877cb4d3eSLandon J. Fuller  * @param[out] name If not NULL, a pointer to the name string. This argument
99977cb4d3eSLandon J. Fuller  * may be NULL.
100077cb4d3eSLandon J. Fuller  * @param[out] name_len On success, the length of the name substring. This
100177cb4d3eSLandon J. Fuller  * argument may be NULL.
100277cb4d3eSLandon J. Fuller  * @param[out] value On success, a pointer to the value substring. This argument
100377cb4d3eSLandon J. Fuller  * may be NULL.
100477cb4d3eSLandon J. Fuller  * @param[out] value_len On success, the length of the value substring. This
100577cb4d3eSLandon J. Fuller  * argument may be NULL.
100677cb4d3eSLandon J. Fuller  *
100777cb4d3eSLandon J. Fuller  * @retval 0 success
100877cb4d3eSLandon J. Fuller  * @retval EINVAL if parsing @p envp fails.
100977cb4d3eSLandon J. Fuller  */
101077cb4d3eSLandon J. Fuller int
bhnd_nvram_parse_env(const char * env,size_t env_len,char delim,const char ** name,size_t * name_len,const char ** value,size_t * value_len)101177cb4d3eSLandon J. Fuller bhnd_nvram_parse_env(const char *env, size_t env_len, char delim,
101277cb4d3eSLandon J. Fuller     const char **name, size_t *name_len, const char **value, size_t *value_len)
101377cb4d3eSLandon J. Fuller {
101477cb4d3eSLandon J. Fuller 	const char *p;
101577cb4d3eSLandon J. Fuller 
101677cb4d3eSLandon J. Fuller 	/* Name */
101777cb4d3eSLandon J. Fuller 	if ((p = memchr(env, delim, env_len)) == NULL) {
101877cb4d3eSLandon J. Fuller 		BHND_NV_LOG("delimiter '%c' not found in '%.*s'\n", delim,
101977cb4d3eSLandon J. Fuller 		    BHND_NV_PRINT_WIDTH(env_len), env);
102077cb4d3eSLandon J. Fuller 		return (EINVAL);
102177cb4d3eSLandon J. Fuller 	}
102277cb4d3eSLandon J. Fuller 
102377cb4d3eSLandon J. Fuller 	/* Name */
102477cb4d3eSLandon J. Fuller 	if (name != NULL)
102577cb4d3eSLandon J. Fuller 		*name = env;
102677cb4d3eSLandon J. Fuller 	if (name_len != NULL)
102777cb4d3eSLandon J. Fuller 		*name_len = p - env;
102877cb4d3eSLandon J. Fuller 
102977cb4d3eSLandon J. Fuller 	/* Skip delim */
103077cb4d3eSLandon J. Fuller 	p++;
103177cb4d3eSLandon J. Fuller 
103277cb4d3eSLandon J. Fuller 	/* Value */
103377cb4d3eSLandon J. Fuller 	if (value != NULL)
103477cb4d3eSLandon J. Fuller 		*value = p;
103577cb4d3eSLandon J. Fuller 	if (value_len != NULL)
103677cb4d3eSLandon J. Fuller 		*value_len = env_len - (p - env);
103777cb4d3eSLandon J. Fuller 
103877cb4d3eSLandon J. Fuller 	return (0);
103977cb4d3eSLandon J. Fuller }
104077cb4d3eSLandon J. Fuller 
104177cb4d3eSLandon J. Fuller /**
104277cb4d3eSLandon J. Fuller  * Parse a field value, returning the actual pointer to the first
104377cb4d3eSLandon J. Fuller  * non-whitespace character and the total size of the field.
104477cb4d3eSLandon J. Fuller  *
104577cb4d3eSLandon J. Fuller  * @param[in,out] inp The field string to parse. Will be updated to point
104677cb4d3eSLandon J. Fuller  * at the first non-whitespace character found.
104777cb4d3eSLandon J. Fuller  * @param ilen The length of @p inp, in bytes.
104877cb4d3eSLandon J. Fuller  * @param delim The field delimiter to search for.
104977cb4d3eSLandon J. Fuller  *
105077cb4d3eSLandon J. Fuller  * @return Returns the actual size of the field data.
105177cb4d3eSLandon J. Fuller  */
105277cb4d3eSLandon J. Fuller size_t
bhnd_nvram_parse_field(const char ** inp,size_t ilen,char delim)105377cb4d3eSLandon J. Fuller bhnd_nvram_parse_field(const char **inp, size_t ilen, char delim)
105477cb4d3eSLandon J. Fuller {
105577cb4d3eSLandon J. Fuller 	const char	*p, *sp;
105677cb4d3eSLandon J. Fuller 
105777cb4d3eSLandon J. Fuller 	/* Skip any leading whitespace */
105877cb4d3eSLandon J. Fuller 	for (sp = *inp; (size_t)(sp-*inp) < ilen && bhnd_nv_isspace(*sp); sp++)
105977cb4d3eSLandon J. Fuller 		continue;
106077cb4d3eSLandon J. Fuller 
106177cb4d3eSLandon J. Fuller 	*inp = sp;
106277cb4d3eSLandon J. Fuller 
106377cb4d3eSLandon J. Fuller 	/* Find the last field character */
106477cb4d3eSLandon J. Fuller 	for (p = *inp; (size_t)(p - *inp) < ilen; p++) {
106577cb4d3eSLandon J. Fuller 		if (*p == delim || *p == '\0')
106677cb4d3eSLandon J. Fuller 			break;
106777cb4d3eSLandon J. Fuller 	}
106877cb4d3eSLandon J. Fuller 
106977cb4d3eSLandon J. Fuller 	return (p - *inp);
107077cb4d3eSLandon J. Fuller }
107177cb4d3eSLandon J. Fuller 
107277cb4d3eSLandon J. Fuller /**
107377cb4d3eSLandon J. Fuller  * Parse a field value, returning the actual pointer to the first
107477cb4d3eSLandon J. Fuller  * non-whitespace character and the total size of the field, minus
107577cb4d3eSLandon J. Fuller  * any trailing whitespace.
107677cb4d3eSLandon J. Fuller  *
107777cb4d3eSLandon J. Fuller  * @param[in,out] inp The field string to parse. Will be updated to point
107877cb4d3eSLandon J. Fuller  * at the first non-whitespace character found.
107977cb4d3eSLandon J. Fuller  * @param ilen The length of the parsed field, in bytes, excluding the
108077cb4d3eSLandon J. Fuller  * field elimiter and any trailing whitespace.
108177cb4d3eSLandon J. Fuller  * @param delim The field delimiter to search for.
108277cb4d3eSLandon J. Fuller  *
108377cb4d3eSLandon J. Fuller  * @return Returns the actual size of the field data.
108477cb4d3eSLandon J. Fuller  */
108577cb4d3eSLandon J. Fuller size_t
bhnd_nvram_trim_field(const char ** inp,size_t ilen,char delim)108677cb4d3eSLandon J. Fuller bhnd_nvram_trim_field(const char **inp, size_t ilen, char delim)
108777cb4d3eSLandon J. Fuller {
108877cb4d3eSLandon J. Fuller 	const char	*sp;
108977cb4d3eSLandon J. Fuller 	size_t		 plen;
109077cb4d3eSLandon J. Fuller 
109177cb4d3eSLandon J. Fuller 	plen = bhnd_nvram_parse_field(inp, ilen, delim);
109277cb4d3eSLandon J. Fuller 
109377cb4d3eSLandon J. Fuller 	/* Trim trailing whitespace */
109477cb4d3eSLandon J. Fuller 	sp = *inp;
109577cb4d3eSLandon J. Fuller 	while (plen > 0) {
109677cb4d3eSLandon J. Fuller 		if (!bhnd_nv_isspace(*(sp + plen - 1)))
109777cb4d3eSLandon J. Fuller 			break;
109877cb4d3eSLandon J. Fuller 
109977cb4d3eSLandon J. Fuller 		plen--;
110077cb4d3eSLandon J. Fuller 	}
110177cb4d3eSLandon J. Fuller 
110277cb4d3eSLandon J. Fuller 	return (plen);
110377cb4d3eSLandon J. Fuller }
1104