xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c (revision d2747968c068b8cfc890901f4955037bad7adb9a)
177cb4d3eSLandon J. Fuller /*-
277cb4d3eSLandon J. Fuller  * Copyright (c) 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/cdefs.h>
3177cb4d3eSLandon J. Fuller #ifdef _KERNEL
3277cb4d3eSLandon J. Fuller 
3377cb4d3eSLandon J. Fuller #include <sys/param.h>
3477cb4d3eSLandon J. Fuller #include <sys/ctype.h>
3577cb4d3eSLandon J. Fuller #include <sys/malloc.h>
3677cb4d3eSLandon J. Fuller #include <sys/systm.h>
3777cb4d3eSLandon J. Fuller 
3877cb4d3eSLandon J. Fuller #else /* !_KERNEL */
3977cb4d3eSLandon J. Fuller 
4077cb4d3eSLandon J. Fuller #include <ctype.h>
4177cb4d3eSLandon J. Fuller #include <stdint.h>
4277cb4d3eSLandon J. Fuller #include <stdio.h>
4377cb4d3eSLandon J. Fuller #include <stdlib.h>
4477cb4d3eSLandon J. Fuller #include <string.h>
4577cb4d3eSLandon J. Fuller 
4677cb4d3eSLandon J. Fuller #endif /* _KERNEL */
4777cb4d3eSLandon J. Fuller 
4877cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
4977cb4d3eSLandon J. Fuller 
5077cb4d3eSLandon J. Fuller #include "bhnd_nvram_datavar.h"
51591e79bcSLandon J. Fuller #include "bhnd_nvram_data_bcmvar.h"
5277cb4d3eSLandon J. Fuller 
5377cb4d3eSLandon J. Fuller /*
5477cb4d3eSLandon J. Fuller  * Broadcom-RAW NVRAM data class.
5577cb4d3eSLandon J. Fuller  *
5677cb4d3eSLandon J. Fuller  * The Broadcom NVRAM NUL-delimited ASCII format is used by most
5777cb4d3eSLandon J. Fuller  * Broadcom SoCs.
5877cb4d3eSLandon J. Fuller  *
59*d2747968SGordon Bergling  * The NVRAM data is encoded as a stream of NUL-terminated 'key=value'
6077cb4d3eSLandon J. Fuller  * strings; the end of the stream is denoted by a single extra NUL character.
6177cb4d3eSLandon J. Fuller  */
6277cb4d3eSLandon J. Fuller 
6377cb4d3eSLandon J. Fuller struct bhnd_nvram_bcmraw;
6477cb4d3eSLandon J. Fuller 
6577cb4d3eSLandon J. Fuller /** BCM-RAW NVRAM data class instance */
6677cb4d3eSLandon J. Fuller struct bhnd_nvram_bcmraw {
6777cb4d3eSLandon J. Fuller 	struct bhnd_nvram_data		 nv;	/**< common instance state */
6877cb4d3eSLandon J. Fuller 	char				*data;	/**< backing buffer */
6977cb4d3eSLandon J. Fuller 	size_t				 size;	/**< buffer size */
7077cb4d3eSLandon J. Fuller 	size_t				 count;	/**< variable count */
7177cb4d3eSLandon J. Fuller };
7277cb4d3eSLandon J. Fuller 
7377cb4d3eSLandon J. Fuller BHND_NVRAM_DATA_CLASS_DEFN(bcmraw, "Broadcom (RAW)",
74c283839dSLandon J. Fuller     BHND_NVRAM_DATA_CAP_DEVPATHS, sizeof(struct bhnd_nvram_bcmraw))
7577cb4d3eSLandon J. Fuller 
7677cb4d3eSLandon J. Fuller static int
7777cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_probe(struct bhnd_nvram_io *io)
7877cb4d3eSLandon J. Fuller {
7977cb4d3eSLandon J. Fuller 	char	 envp[16];
8077cb4d3eSLandon J. Fuller 	size_t	 envp_len;
81a7c43ebdSLandon J. Fuller 	size_t	 io_size;
8277cb4d3eSLandon J. Fuller 	int	 error;
8377cb4d3eSLandon J. Fuller 
84a7c43ebdSLandon J. Fuller 	io_size = bhnd_nvram_io_getsize(io);
85a7c43ebdSLandon J. Fuller 
8677cb4d3eSLandon J. Fuller 	/*
87a7c43ebdSLandon J. Fuller 	 * Fetch initial bytes
8877cb4d3eSLandon J. Fuller 	 */
89a7c43ebdSLandon J. Fuller 	envp_len = bhnd_nv_ummin(sizeof(envp), io_size);
9077cb4d3eSLandon J. Fuller 	if ((error = bhnd_nvram_io_read(io, 0x0, envp, envp_len)))
9177cb4d3eSLandon J. Fuller 		return (error);
9277cb4d3eSLandon J. Fuller 
93a7c43ebdSLandon J. Fuller 	/* An empty BCM-RAW buffer should still contain a single terminating
9477cb4d3eSLandon J. Fuller 	 * NUL */
9577cb4d3eSLandon J. Fuller 	if (envp_len == 0)
9677cb4d3eSLandon J. Fuller 		return (ENXIO);
9777cb4d3eSLandon J. Fuller 
9877cb4d3eSLandon J. Fuller 	if (envp_len == 1) {
9977cb4d3eSLandon J. Fuller 		if (envp[0] != '\0')
10077cb4d3eSLandon J. Fuller 			return (ENXIO);
10177cb4d3eSLandon J. Fuller 
10277cb4d3eSLandon J. Fuller 		return (BHND_NVRAM_DATA_PROBE_MAYBE);
10377cb4d3eSLandon J. Fuller 	}
10477cb4d3eSLandon J. Fuller 
105a7c43ebdSLandon J. Fuller 	/* Must contain only printable ASCII characters delimited
106a7c43ebdSLandon J. Fuller 	 * by NUL record delimiters */
10777cb4d3eSLandon J. Fuller 	for (size_t i = 0; i < envp_len; i++) {
10877cb4d3eSLandon J. Fuller 		char c = envp[i];
10977cb4d3eSLandon J. Fuller 
110a7c43ebdSLandon J. Fuller 		/* If we hit a newline, this is probably BCM-TXT */
111a7c43ebdSLandon J. Fuller 		if (c == '\n')
11277cb4d3eSLandon J. Fuller 			return (ENXIO);
113a7c43ebdSLandon J. Fuller 
114a7c43ebdSLandon J. Fuller 		if (c == '\0' && !bhnd_nv_isprint(c))
115a7c43ebdSLandon J. Fuller 			continue;
11677cb4d3eSLandon J. Fuller 	}
11777cb4d3eSLandon J. Fuller 
118a7c43ebdSLandon J. Fuller 	/* A valid BCM-RAW buffer should contain a terminating NUL for
119a7c43ebdSLandon J. Fuller 	 * the last record, followed by a final empty record terminated by
120a7c43ebdSLandon J. Fuller 	 * NUL */
121a7c43ebdSLandon J. Fuller 	envp_len = 2;
122a7c43ebdSLandon J. Fuller 	if (io_size < envp_len)
12377cb4d3eSLandon J. Fuller 		return (ENXIO);
12477cb4d3eSLandon J. Fuller 
125a7c43ebdSLandon J. Fuller 	if ((error = bhnd_nvram_io_read(io, io_size-envp_len, envp, envp_len)))
126a7c43ebdSLandon J. Fuller 		return (error);
127a7c43ebdSLandon J. Fuller 
128a7c43ebdSLandon J. Fuller 	if (envp[0] != '\0' || envp[1] != '\0')
129a7c43ebdSLandon J. Fuller 		return (ENXIO);
130a7c43ebdSLandon J. Fuller 
131a7c43ebdSLandon J. Fuller 	return (BHND_NVRAM_DATA_PROBE_MAYBE + 1);
13277cb4d3eSLandon J. Fuller }
13377cb4d3eSLandon J. Fuller 
134c283839dSLandon J. Fuller static int
135591e79bcSLandon J. Fuller bhnd_nvram_bcmraw_getvar_direct(struct bhnd_nvram_io *io, const char *name,
136591e79bcSLandon J. Fuller     void *buf, size_t *len, bhnd_nvram_type type)
137591e79bcSLandon J. Fuller {
138591e79bcSLandon J. Fuller 	return (bhnd_nvram_bcm_getvar_direct_common(io, name, buf, len, type,
139591e79bcSLandon J. Fuller 	    false));
140591e79bcSLandon J. Fuller }
141591e79bcSLandon J. Fuller 
142591e79bcSLandon J. Fuller static int
143c283839dSLandon J. Fuller bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
144c283839dSLandon J. Fuller     bhnd_nvram_plist *options, void *outp, size_t *olen)
145c283839dSLandon J. Fuller {
146c283839dSLandon J. Fuller 	bhnd_nvram_prop	*prop;
147c283839dSLandon J. Fuller 	size_t		 limit, nbytes;
148c283839dSLandon J. Fuller 	int		 error;
149c283839dSLandon J. Fuller 
150c283839dSLandon J. Fuller 	/* Determine output byte limit */
151c283839dSLandon J. Fuller 	if (outp != NULL)
152c283839dSLandon J. Fuller 		limit = *olen;
153c283839dSLandon J. Fuller 	else
154c283839dSLandon J. Fuller 		limit = 0;
155c283839dSLandon J. Fuller 
156c283839dSLandon J. Fuller 	nbytes = 0;
157c283839dSLandon J. Fuller 
158c283839dSLandon J. Fuller 	/* Write all properties */
159c283839dSLandon J. Fuller 	prop = NULL;
160c283839dSLandon J. Fuller 	while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
161c283839dSLandon J. Fuller 		const char	*name;
162c283839dSLandon J. Fuller 		char		*p;
163c283839dSLandon J. Fuller 		size_t		 prop_limit;
164c283839dSLandon J. Fuller 		size_t		 name_len, value_len;
165c283839dSLandon J. Fuller 
166c283839dSLandon J. Fuller 		if (outp == NULL || limit < nbytes) {
167c283839dSLandon J. Fuller 			p = NULL;
168c283839dSLandon J. Fuller 			prop_limit = 0;
169c283839dSLandon J. Fuller 		} else {
170c283839dSLandon J. Fuller 			p = ((char *)outp) + nbytes;
171c283839dSLandon J. Fuller 			prop_limit = limit - nbytes;
172c283839dSLandon J. Fuller 		}
173c283839dSLandon J. Fuller 
174c283839dSLandon J. Fuller 		/* Fetch and write name + '=' to output */
175c283839dSLandon J. Fuller 		name = bhnd_nvram_prop_name(prop);
176c283839dSLandon J. Fuller 		name_len = strlen(name) + 1;
177c283839dSLandon J. Fuller 
178c283839dSLandon J. Fuller 		if (prop_limit > name_len) {
179c283839dSLandon J. Fuller 			memcpy(p, name, name_len - 1);
180c283839dSLandon J. Fuller 			p[name_len - 1] = '=';
181c283839dSLandon J. Fuller 
182c283839dSLandon J. Fuller 			prop_limit -= name_len;
183c283839dSLandon J. Fuller 			p += name_len;
184c283839dSLandon J. Fuller 		} else {
185c283839dSLandon J. Fuller 			prop_limit = 0;
186c283839dSLandon J. Fuller 			p = NULL;
187c283839dSLandon J. Fuller 		}
188c283839dSLandon J. Fuller 
189c283839dSLandon J. Fuller 		/* Advance byte count */
190c283839dSLandon J. Fuller 		if (SIZE_MAX - nbytes < name_len)
191c283839dSLandon J. Fuller 			return (EFTYPE); /* would overflow size_t */
192c283839dSLandon J. Fuller 
193c283839dSLandon J. Fuller 		nbytes += name_len;
194c283839dSLandon J. Fuller 
195c283839dSLandon J. Fuller 		/* Attempt to write NUL-terminated value to output */
196c283839dSLandon J. Fuller 		value_len = prop_limit;
197c283839dSLandon J. Fuller 		error = bhnd_nvram_prop_encode(prop, p, &value_len,
198c283839dSLandon J. Fuller 		    BHND_NVRAM_TYPE_STRING);
199c283839dSLandon J. Fuller 
200c283839dSLandon J. Fuller 		/* If encoding failed for any reason other than ENOMEM (which
201c283839dSLandon J. Fuller 		 * we'll detect and report after encoding all properties),
202c283839dSLandon J. Fuller 		 * return immediately */
203c283839dSLandon J. Fuller 		if (error && error != ENOMEM) {
204c283839dSLandon J. Fuller 			BHND_NV_LOG("error serializing %s to required type "
205c283839dSLandon J. Fuller 			    "%s: %d\n", name,
206c283839dSLandon J. Fuller 			    bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
207c283839dSLandon J. Fuller 			    error);
208c283839dSLandon J. Fuller 			return (error);
209c283839dSLandon J. Fuller 		}
210c283839dSLandon J. Fuller 
211c283839dSLandon J. Fuller 		/* Advance byte count */
212c283839dSLandon J. Fuller 		if (SIZE_MAX - nbytes < value_len)
213c283839dSLandon J. Fuller 			return (EFTYPE); /* would overflow size_t */
214c283839dSLandon J. Fuller 
215c283839dSLandon J. Fuller 		nbytes += value_len;
216c283839dSLandon J. Fuller 	}
217c283839dSLandon J. Fuller 
218c283839dSLandon J. Fuller 	/* Write terminating '\0' */
219c283839dSLandon J. Fuller 	if (limit > nbytes)
220c283839dSLandon J. Fuller 		*((char *)outp + nbytes) = '\0';
221c283839dSLandon J. Fuller 
222c283839dSLandon J. Fuller 	if (nbytes == SIZE_MAX)
223c283839dSLandon J. Fuller 		return (EFTYPE); /* would overflow size_t */
224c283839dSLandon J. Fuller 	else
225c283839dSLandon J. Fuller 		nbytes++;
226c283839dSLandon J. Fuller 
227c283839dSLandon J. Fuller 	/* Provide required length */
228c283839dSLandon J. Fuller 	*olen = nbytes;
229c283839dSLandon J. Fuller 	if (limit < *olen) {
230c283839dSLandon J. Fuller 		if (outp == NULL)
231c283839dSLandon J. Fuller 			return (0);
232c283839dSLandon J. Fuller 
233c283839dSLandon J. Fuller 		return (ENOMEM);
234c283839dSLandon J. Fuller 	}
235c283839dSLandon J. Fuller 
236c283839dSLandon J. Fuller 	return (0);
237c283839dSLandon J. Fuller }
238c283839dSLandon J. Fuller 
23977cb4d3eSLandon J. Fuller /**
24077cb4d3eSLandon J. Fuller  * Initialize @p bcm with the provided NVRAM data mapped by @p src.
24177cb4d3eSLandon J. Fuller  *
24277cb4d3eSLandon J. Fuller  * @param bcm A newly allocated data instance.
24377cb4d3eSLandon J. Fuller  */
24477cb4d3eSLandon J. Fuller static int
24577cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_init(struct bhnd_nvram_bcmraw *bcm, struct bhnd_nvram_io *src)
24677cb4d3eSLandon J. Fuller {
24777cb4d3eSLandon J. Fuller 	size_t	 io_size;
24877cb4d3eSLandon J. Fuller 	size_t	 capacity, offset;
24977cb4d3eSLandon J. Fuller 	int	 error;
25077cb4d3eSLandon J. Fuller 
25177cb4d3eSLandon J. Fuller 	/* Fetch the input image size */
25277cb4d3eSLandon J. Fuller 	io_size = bhnd_nvram_io_getsize(src);
25377cb4d3eSLandon J. Fuller 
25477cb4d3eSLandon J. Fuller 	/* Allocate a buffer large enough to hold the NVRAM image, and
25577cb4d3eSLandon J. Fuller 	 * an extra EOF-signaling NUL (on the chance it's missing from the
25677cb4d3eSLandon J. Fuller 	 * source data) */
25777cb4d3eSLandon J. Fuller 	if (io_size == SIZE_MAX)
25877cb4d3eSLandon J. Fuller 		return (ENOMEM);
25977cb4d3eSLandon J. Fuller 
26077cb4d3eSLandon J. Fuller 	capacity = io_size + 1 /* room for extra NUL */;
26177cb4d3eSLandon J. Fuller 	bcm->size = io_size;
26277cb4d3eSLandon J. Fuller 	if ((bcm->data = bhnd_nv_malloc(capacity)) == NULL)
26377cb4d3eSLandon J. Fuller 		return (ENOMEM);
26477cb4d3eSLandon J. Fuller 
26577cb4d3eSLandon J. Fuller 	/* Copy in the NVRAM image */
26677cb4d3eSLandon J. Fuller 	if ((error = bhnd_nvram_io_read(src, 0x0, bcm->data, io_size)))
26777cb4d3eSLandon J. Fuller 		return (error);
26877cb4d3eSLandon J. Fuller 
26977cb4d3eSLandon J. Fuller 	/* Process the buffer */
27077cb4d3eSLandon J. Fuller 	bcm->count = 0;
27177cb4d3eSLandon J. Fuller 	for (offset = 0; offset < bcm->size; offset++) {
27277cb4d3eSLandon J. Fuller 		char		*envp;
27377cb4d3eSLandon J. Fuller 		const char	*name, *value;
27477cb4d3eSLandon J. Fuller 		size_t		 envp_len;
27577cb4d3eSLandon J. Fuller 		size_t		 name_len, value_len;
27677cb4d3eSLandon J. Fuller 
27777cb4d3eSLandon J. Fuller 		/* Parse the key=value string */
27877cb4d3eSLandon J. Fuller 		envp = (char *) (bcm->data + offset);
27977cb4d3eSLandon J. Fuller 		envp_len = strnlen(envp, bcm->size - offset);
28077cb4d3eSLandon J. Fuller 		error = bhnd_nvram_parse_env(envp, envp_len, '=', &name,
28177cb4d3eSLandon J. Fuller 					     &name_len, &value, &value_len);
28277cb4d3eSLandon J. Fuller 		if (error) {
28377cb4d3eSLandon J. Fuller 			BHND_NV_LOG("error parsing envp at offset %#zx: %d\n",
28477cb4d3eSLandon J. Fuller 			    offset, error);
28577cb4d3eSLandon J. Fuller 			return (error);
28677cb4d3eSLandon J. Fuller 		}
28777cb4d3eSLandon J. Fuller 
28877cb4d3eSLandon J. Fuller 		/* Insert a '\0' character, replacing the '=' delimiter and
28977cb4d3eSLandon J. Fuller 		 * allowing us to vend references directly to the variable
29077cb4d3eSLandon J. Fuller 		 * name */
29177cb4d3eSLandon J. Fuller 		*(envp + name_len) = '\0';
29277cb4d3eSLandon J. Fuller 
29377cb4d3eSLandon J. Fuller 		/* Add to variable count */
29477cb4d3eSLandon J. Fuller 		bcm->count++;
29577cb4d3eSLandon J. Fuller 
29677cb4d3eSLandon J. Fuller 		/* Seek past the value's terminating '\0' */
29777cb4d3eSLandon J. Fuller 		offset += envp_len;
29877cb4d3eSLandon J. Fuller 		if (offset == io_size) {
29977cb4d3eSLandon J. Fuller 			BHND_NV_LOG("missing terminating NUL at offset %#zx\n",
30077cb4d3eSLandon J. Fuller 			    offset);
30177cb4d3eSLandon J. Fuller 			return (EINVAL);
30277cb4d3eSLandon J. Fuller 		}
30377cb4d3eSLandon J. Fuller 
30477cb4d3eSLandon J. Fuller 		/* If we hit EOF without finding a terminating NUL
30577cb4d3eSLandon J. Fuller 		 * byte, we need to append it */
30677cb4d3eSLandon J. Fuller 		if (++offset == bcm->size) {
30777cb4d3eSLandon J. Fuller 			BHND_NV_ASSERT(offset < capacity,
30877cb4d3eSLandon J. Fuller 			    ("appending past end of buffer"));
30977cb4d3eSLandon J. Fuller 			bcm->size++;
31077cb4d3eSLandon J. Fuller 			*(bcm->data + offset) = '\0';
31177cb4d3eSLandon J. Fuller 		}
31277cb4d3eSLandon J. Fuller 
31377cb4d3eSLandon J. Fuller 		/* Check for explicit EOF (encoded as a single empty NUL
31477cb4d3eSLandon J. Fuller 		 * terminated string) */
31577cb4d3eSLandon J. Fuller 		if (*(bcm->data + offset) == '\0')
31677cb4d3eSLandon J. Fuller 			break;
31777cb4d3eSLandon J. Fuller 	}
31877cb4d3eSLandon J. Fuller 
319ce99e4faSGordon Bergling 	/* Reclaim any unused space in the backing buffer */
32077cb4d3eSLandon J. Fuller 	if (offset < bcm->size) {
32177cb4d3eSLandon J. Fuller 		bcm->data = bhnd_nv_reallocf(bcm->data, bcm->size);
32277cb4d3eSLandon J. Fuller 		if (bcm->data == NULL)
32377cb4d3eSLandon J. Fuller 			return (ENOMEM);
32477cb4d3eSLandon J. Fuller 	}
32577cb4d3eSLandon J. Fuller 
32677cb4d3eSLandon J. Fuller 	return (0);
32777cb4d3eSLandon J. Fuller }
32877cb4d3eSLandon J. Fuller 
32977cb4d3eSLandon J. Fuller static int
33077cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
33177cb4d3eSLandon J. Fuller {
33277cb4d3eSLandon J. Fuller 	struct bhnd_nvram_bcmraw	*bcm;
33377cb4d3eSLandon J. Fuller 	int				 error;
33477cb4d3eSLandon J. Fuller 
33577cb4d3eSLandon J. Fuller 	bcm = (struct bhnd_nvram_bcmraw *)nv;
33677cb4d3eSLandon J. Fuller 
33777cb4d3eSLandon J. Fuller 	/* Parse the BCM input data and initialize our backing
33877cb4d3eSLandon J. Fuller 	 * data representation */
33977cb4d3eSLandon J. Fuller 	if ((error = bhnd_nvram_bcmraw_init(bcm, io))) {
34077cb4d3eSLandon J. Fuller 		bhnd_nvram_bcmraw_free(nv);
34177cb4d3eSLandon J. Fuller 		return (error);
34277cb4d3eSLandon J. Fuller 	}
34377cb4d3eSLandon J. Fuller 
34477cb4d3eSLandon J. Fuller 	return (0);
34577cb4d3eSLandon J. Fuller }
34677cb4d3eSLandon J. Fuller 
34777cb4d3eSLandon J. Fuller static void
34877cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_free(struct bhnd_nvram_data *nv)
34977cb4d3eSLandon J. Fuller {
35077cb4d3eSLandon J. Fuller 	struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
35177cb4d3eSLandon J. Fuller 
35277cb4d3eSLandon J. Fuller 	if (bcm->data != NULL)
35377cb4d3eSLandon J. Fuller 		bhnd_nv_free(bcm->data);
35477cb4d3eSLandon J. Fuller }
35577cb4d3eSLandon J. Fuller 
356a7c43ebdSLandon J. Fuller static bhnd_nvram_plist *
357a7c43ebdSLandon J. Fuller bhnd_nvram_bcmraw_options(struct bhnd_nvram_data *nv)
358a7c43ebdSLandon J. Fuller {
359a7c43ebdSLandon J. Fuller 	return (NULL);
360a7c43ebdSLandon J. Fuller }
361a7c43ebdSLandon J. Fuller 
362c283839dSLandon J. Fuller static size_t
363c283839dSLandon J. Fuller bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
36477cb4d3eSLandon J. Fuller {
365c283839dSLandon J. Fuller 	struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
36677cb4d3eSLandon J. Fuller 
367c283839dSLandon J. Fuller 	return (bcm->count);
36877cb4d3eSLandon J. Fuller }
36977cb4d3eSLandon J. Fuller 
37077cb4d3eSLandon J. Fuller static uint32_t
37177cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_caps(struct bhnd_nvram_data *nv)
37277cb4d3eSLandon J. Fuller {
37377cb4d3eSLandon J. Fuller 	return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
37477cb4d3eSLandon J. Fuller }
37577cb4d3eSLandon J. Fuller 
37677cb4d3eSLandon J. Fuller static const char *
37777cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_next(struct bhnd_nvram_data *nv, void **cookiep)
37877cb4d3eSLandon J. Fuller {
37977cb4d3eSLandon J. Fuller 	struct bhnd_nvram_bcmraw	*bcm;
38077cb4d3eSLandon J. Fuller 	const char			*envp;
38177cb4d3eSLandon J. Fuller 
38277cb4d3eSLandon J. Fuller 	bcm = (struct bhnd_nvram_bcmraw *)nv;
38377cb4d3eSLandon J. Fuller 
38477cb4d3eSLandon J. Fuller 	if (*cookiep == NULL) {
38577cb4d3eSLandon J. Fuller 		/* Start at the first NVRAM data record */
38677cb4d3eSLandon J. Fuller 		envp = bcm->data;
38777cb4d3eSLandon J. Fuller 	} else {
38877cb4d3eSLandon J. Fuller 		/* Seek to next record */
38977cb4d3eSLandon J. Fuller 		envp = *cookiep;
39077cb4d3eSLandon J. Fuller 		envp += strlen(envp) + 1;	/* key + '\0' */
39177cb4d3eSLandon J. Fuller 		envp += strlen(envp) + 1;	/* value + '\0' */
39277cb4d3eSLandon J. Fuller 	}
39377cb4d3eSLandon J. Fuller 
39477cb4d3eSLandon J. Fuller 	/* EOF? */
39577cb4d3eSLandon J. Fuller 	if (*envp == '\0')
39677cb4d3eSLandon J. Fuller 		return (NULL);
39777cb4d3eSLandon J. Fuller 
39877cb4d3eSLandon J. Fuller 	*cookiep = (void *)(uintptr_t)envp;
39977cb4d3eSLandon J. Fuller 	return (envp);
40077cb4d3eSLandon J. Fuller }
40177cb4d3eSLandon J. Fuller 
40277cb4d3eSLandon J. Fuller static void *
40377cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_find(struct bhnd_nvram_data *nv, const char *name)
40477cb4d3eSLandon J. Fuller {
40577cb4d3eSLandon J. Fuller 	return (bhnd_nvram_data_generic_find(nv, name));
40677cb4d3eSLandon J. Fuller }
40777cb4d3eSLandon J. Fuller 
40877cb4d3eSLandon J. Fuller static int
40919be09f3SLandon J. Fuller bhnd_nvram_bcmraw_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
41019be09f3SLandon J. Fuller     void *cookiep2)
41119be09f3SLandon J. Fuller {
41219be09f3SLandon J. Fuller 	if (cookiep1 < cookiep2)
41319be09f3SLandon J. Fuller 		return (-1);
41419be09f3SLandon J. Fuller 
41519be09f3SLandon J. Fuller 	if (cookiep1 > cookiep2)
41619be09f3SLandon J. Fuller 		return (1);
41719be09f3SLandon J. Fuller 
41819be09f3SLandon J. Fuller 	return (0);
41919be09f3SLandon J. Fuller }
42019be09f3SLandon J. Fuller 
42119be09f3SLandon J. Fuller static int
42277cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
42377cb4d3eSLandon J. Fuller     size_t *len, bhnd_nvram_type type)
42477cb4d3eSLandon J. Fuller {
42577cb4d3eSLandon J. Fuller 	return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
42677cb4d3eSLandon J. Fuller }
42777cb4d3eSLandon J. Fuller 
42819be09f3SLandon J. Fuller static int
42919be09f3SLandon J. Fuller bhnd_nvram_bcmraw_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
43019be09f3SLandon J. Fuller     bhnd_nvram_val **value)
43119be09f3SLandon J. Fuller {
43219be09f3SLandon J. Fuller 	return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
43319be09f3SLandon J. Fuller }
43419be09f3SLandon J. Fuller 
43577cb4d3eSLandon J. Fuller static const void *
43677cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
43777cb4d3eSLandon J. Fuller     size_t *len, bhnd_nvram_type *type)
43877cb4d3eSLandon J. Fuller {
43977cb4d3eSLandon J. Fuller 	const char *envp;
44077cb4d3eSLandon J. Fuller 
44177cb4d3eSLandon J. Fuller 	/* Cookie points to key\0value\0 -- get the value address */
44277cb4d3eSLandon J. Fuller 	envp = cookiep;
44377cb4d3eSLandon J. Fuller 	envp += strlen(envp) + 1;	/* key + '\0' */
44477cb4d3eSLandon J. Fuller 	*len = strlen(envp) + 1;	/* value + '\0' */
44577cb4d3eSLandon J. Fuller 	*type = BHND_NVRAM_TYPE_STRING;
44677cb4d3eSLandon J. Fuller 
44777cb4d3eSLandon J. Fuller 	return (envp);
44877cb4d3eSLandon J. Fuller }
44977cb4d3eSLandon J. Fuller 
45077cb4d3eSLandon J. Fuller static const char *
45177cb4d3eSLandon J. Fuller bhnd_nvram_bcmraw_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
45277cb4d3eSLandon J. Fuller {
45377cb4d3eSLandon J. Fuller 	/* Cookie points to key\0value\0 */
45477cb4d3eSLandon J. Fuller 	return (cookiep);
45577cb4d3eSLandon J. Fuller }
45619be09f3SLandon J. Fuller 
45719be09f3SLandon J. Fuller static int
45819be09f3SLandon J. Fuller bhnd_nvram_bcmraw_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
45919be09f3SLandon J. Fuller     bhnd_nvram_val *value, bhnd_nvram_val **result)
46019be09f3SLandon J. Fuller {
46119be09f3SLandon J. Fuller 	bhnd_nvram_val	*str;
46219be09f3SLandon J. Fuller 	int		 error;
46319be09f3SLandon J. Fuller 
46419be09f3SLandon J. Fuller 	/* Name (trimmed of any path prefix) must be valid */
46519be09f3SLandon J. Fuller 	if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
46619be09f3SLandon J. Fuller 		return (EINVAL);
46719be09f3SLandon J. Fuller 
46819be09f3SLandon J. Fuller 	/* Value must be bcm-formatted string */
46919be09f3SLandon J. Fuller 	error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
47019be09f3SLandon J. Fuller 	    value, BHND_NVRAM_VAL_DYNAMIC);
47119be09f3SLandon J. Fuller 	if (error)
47219be09f3SLandon J. Fuller 		return (error);
47319be09f3SLandon J. Fuller 
47419be09f3SLandon J. Fuller 	/* Success. Transfer result ownership to the caller. */
47519be09f3SLandon J. Fuller 	*result = str;
47619be09f3SLandon J. Fuller 	return (0);
47719be09f3SLandon J. Fuller }
47819be09f3SLandon J. Fuller 
47919be09f3SLandon J. Fuller static int
48019be09f3SLandon J. Fuller bhnd_nvram_bcmraw_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
48119be09f3SLandon J. Fuller {
48219be09f3SLandon J. Fuller 	/* We permit deletion of any variable */
48319be09f3SLandon J. Fuller 	return (0);
48419be09f3SLandon J. Fuller }
485