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