#include <sys/param.h>
#include <sys/endian.h>
#ifdef _KERNEL
#include <sys/bus.h>
#include <sys/ctype.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#else
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
#include "bhnd_nvram_private.h"
#include "bhnd_nvram_datavar.h"
#include "bhnd_nvram_data_bcmreg.h"
#include "bhnd_nvram_data_bcmvar.h"
struct bhnd_nvram_bcm;
static struct bhnd_nvram_bcm_hvar *bhnd_nvram_bcm_gethdrvar(
struct bhnd_nvram_bcm *bcm,
const char *name);
static struct bhnd_nvram_bcm_hvar *bhnd_nvram_bcm_to_hdrvar(
struct bhnd_nvram_bcm *bcm,
void *cookiep);
static size_t bhnd_nvram_bcm_hdrvar_index(
struct bhnd_nvram_bcm *bcm,
struct bhnd_nvram_bcm_hvar *hvar);
static const struct bhnd_nvram_bcm_hvar bhnd_nvram_bcm_hvars[] = {
{
.name = BCM_NVRAM_CFG0_SDRAM_INIT_VAR,
.type = BHND_NVRAM_TYPE_UINT16,
.len = sizeof(uint16_t),
.nelem = 1,
},
{
.name = BCM_NVRAM_CFG1_SDRAM_CFG_VAR,
.type = BHND_NVRAM_TYPE_UINT16,
.len = sizeof(uint16_t),
.nelem = 1,
},
{
.name = BCM_NVRAM_CFG1_SDRAM_REFRESH_VAR,
.type = BHND_NVRAM_TYPE_UINT16,
.len = sizeof(uint16_t),
.nelem = 1,
},
{
.name = BCM_NVRAM_SDRAM_NCDL_VAR,
.type = BHND_NVRAM_TYPE_UINT32,
.len = sizeof(uint32_t),
.nelem = 1,
},
};
struct bhnd_nvram_bcm {
struct bhnd_nvram_data nv;
struct bhnd_nvram_io *data;
bhnd_nvram_plist *opts;
struct bhnd_nvram_bcm_hvar hvars[nitems(bhnd_nvram_bcm_hvars)];
size_t count;
};
BHND_NVRAM_DATA_CLASS_DEFN(bcm, "Broadcom", BHND_NVRAM_DATA_CAP_DEVPATHS,
sizeof(struct bhnd_nvram_bcm))
static int
bhnd_nvram_bcm_probe(struct bhnd_nvram_io *io)
{
struct bhnd_nvram_bcmhdr hdr;
int error;
if ((error = bhnd_nvram_io_read(io, 0x0, &hdr, sizeof(hdr))))
return (error);
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
return (ENXIO);
if (le32toh(hdr.size) > bhnd_nvram_io_getsize(io))
return (ENXIO);
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
}
typedef enum {
BCM_PARSE_KEY_START,
BCM_PARSE_KEY_CONT,
BCM_PARSE_KEY,
BCM_PARSE_NEXT_KEY,
BCM_PARSE_VALUE_START,
BCM_PARSE_VALUE
} bcm_parse_state;
static int
bhnd_nvram_bcm_getvar_direct(struct bhnd_nvram_io *io, const char *name,
void *outp, size_t *olen, bhnd_nvram_type otype)
{
return (bhnd_nvram_bcm_getvar_direct_common(io, name, outp, olen, otype,
true));
}
int
bhnd_nvram_bcm_getvar_direct_common(struct bhnd_nvram_io *io, const char *name,
void *outp, size_t *olen, bhnd_nvram_type otype, bool have_header)
{
struct bhnd_nvram_bcmhdr hdr;
char buf[512];
bcm_parse_state pstate;
size_t limit, offset;
size_t buflen, bufpos;
size_t namelen, namepos;
size_t vlen;
int error;
limit = bhnd_nvram_io_getsize(io);
offset = 0;
if (have_header) {
if ((error = bhnd_nvram_io_read(io, offset, &hdr, sizeof(hdr))))
return (error);
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
return (ENXIO);
offset += sizeof(hdr);
limit = bhnd_nv_ummin(le32toh(hdr.size), limit);
}
pstate = BCM_PARSE_KEY_START;
buflen = 0;
bufpos = 0;
namelen = strlen(name);
namepos = 0;
vlen = 0;
while ((offset - bufpos) < limit) {
BHND_NV_ASSERT(bufpos <= buflen,
("buf position invalid (%zu > %zu)", bufpos, buflen));
BHND_NV_ASSERT(buflen <= sizeof(buf),
("buf length invalid (%zu > %zu", buflen, sizeof(buf)));
if (buflen - bufpos == 0) {
BHND_NV_ASSERT(offset < limit, ("offset overrun"));
buflen = bhnd_nv_ummin(sizeof(buf), limit - offset);
bufpos = 0;
error = bhnd_nvram_io_read(io, offset, buf, buflen);
if (error)
return (error);
offset += buflen;
}
switch (pstate) {
case BCM_PARSE_KEY_START:
BHND_NV_ASSERT(buflen - bufpos > 0, ("empty buffer!"));
if (buf[bufpos] == '\0')
return (ENOENT);
namepos = 0;
pstate = BCM_PARSE_KEY_CONT;
break;
case BCM_PARSE_KEY_CONT: {
size_t navail, nleft;
nleft = namelen - namepos;
navail = bhnd_nv_ummin(buflen - bufpos, nleft);
if (strncmp(name+namepos, buf+bufpos, navail) == 0) {
namepos += navail;
bufpos += navail;
if (namepos == namelen)
pstate = BCM_PARSE_KEY;
} else {
pstate = BCM_PARSE_NEXT_KEY;
}
break;
}
case BCM_PARSE_KEY:
BHND_NV_ASSERT(buflen - bufpos > 0, ("empty buffer!"));
if (buf[bufpos] == '=') {
bufpos++;
pstate = BCM_PARSE_VALUE_START;
} else {
pstate = BCM_PARSE_NEXT_KEY;
}
break;
case BCM_PARSE_NEXT_KEY: {
const char *p;
p = memchr(buf+bufpos, '\0', buflen - bufpos);
if (p != NULL) {
pstate = BCM_PARSE_KEY_START;
bufpos = (p - buf) + 1 ;
} else {
bufpos = buflen;
}
break;
}
case BCM_PARSE_VALUE_START: {
const char *p;
p = memchr(buf+bufpos, '\0', buflen - bufpos);
if (p != NULL) {
vlen = p - &buf[bufpos];
pstate = BCM_PARSE_VALUE;
} else if (p == NULL && offset == limit) {
vlen = buflen - bufpos;
pstate = BCM_PARSE_VALUE;
} else if (p == NULL && bufpos > 0) {
size_t nread;
memmove(buf, buf+bufpos, buflen - bufpos);
buflen = bufpos;
bufpos = 0;
nread = bhnd_nv_ummin(sizeof(buf) - buflen,
limit - offset);
error = bhnd_nvram_io_read(io, offset,
buf+buflen, nread);
if (error)
return (error);
offset += nread;
buflen += nread;
} else {
BHND_NV_LOG("cannot parse value for '%s' "
"(exceeds %zu byte limit)\n", name,
sizeof(buf));
return (ENXIO);
}
break;
}
case BCM_PARSE_VALUE:
BHND_NV_ASSERT(vlen <= buflen, ("value buf overrun"));
return (bhnd_nvram_value_coerce(buf+bufpos, vlen,
BHND_NVRAM_TYPE_STRING, outp, olen, otype));
}
}
return (ENOENT);
}
static int
bhnd_nvram_bcm_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
bhnd_nvram_plist *options, void *outp, size_t *olen)
{
struct bhnd_nvram_bcmhdr hdr;
bhnd_nvram_prop *prop;
size_t limit, nbytes;
uint32_t sdram_ncdl;
uint16_t sdram_init, sdram_cfg, sdram_refresh;
uint8_t bcm_ver, crc8;
int error;
if (outp != NULL)
limit = *olen;
else
limit = 0;
#define PROPS_GET_HDRVAR(_name, _dest, _type) do { \
const char *name = BCM_NVRAM_ ## _name ## _VAR; \
if (!bhnd_nvram_plist_contains(props, name)) { \
BHND_NV_LOG("missing required property: %s\n", \
name); \
return (EFTYPE); \
} \
\
error = bhnd_nvram_plist_get_encoded(props, name, \
(_dest), sizeof(*(_dest)), \
BHND_NVRAM_TYPE_ ##_type); \
if (error) { \
BHND_NV_LOG("error reading required header " \
"%s property: %d\n", name, error); \
return (EFTYPE); \
} \
} while (0)
PROPS_GET_HDRVAR(SDRAM_NCDL, &sdram_ncdl, UINT32);
PROPS_GET_HDRVAR(CFG0_SDRAM_INIT, &sdram_init, UINT16);
PROPS_GET_HDRVAR(CFG1_SDRAM_CFG, &sdram_cfg, UINT16);
PROPS_GET_HDRVAR(CFG1_SDRAM_REFRESH, &sdram_refresh, UINT16);
#undef PROPS_GET_HDRVAR
if (options != NULL &&
bhnd_nvram_plist_contains(options, BCM_NVRAM_ENCODE_OPT_VERSION))
{
error = bhnd_nvram_plist_get_uint8(options,
BCM_NVRAM_ENCODE_OPT_VERSION, &bcm_ver);
if (error) {
BHND_NV_LOG("error reading %s uint8 option value: %d\n",
BCM_NVRAM_ENCODE_OPT_VERSION, error);
return (EINVAL);
}
} else {
bcm_ver = BCM_NVRAM_CFG0_VER_DEFAULT;
}
hdr = (struct bhnd_nvram_bcmhdr) {
.magic = htole32(BCM_NVRAM_MAGIC),
.size = 0,
.cfg0 = 0,
.cfg1 = 0,
.sdram_ncdl = htole32(sdram_ncdl)
};
hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_CRC, 0x0);
hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_VER, bcm_ver);
hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_SDRAM_INIT,
htole16(sdram_init));
hdr.cfg1 = BCM_NVRAM_SET_BITS(hdr.cfg1, BCM_NVRAM_CFG1_SDRAM_CFG,
htole16(sdram_cfg));
hdr.cfg1 = BCM_NVRAM_SET_BITS(hdr.cfg1, BCM_NVRAM_CFG1_SDRAM_REFRESH,
htole16(sdram_refresh));
nbytes = sizeof(hdr);
if (limit >= nbytes)
memcpy(outp, &hdr, sizeof(hdr));
prop = NULL;
while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
const char *name;
char *p;
size_t prop_limit;
size_t name_len, value_len;
if (outp == NULL || limit < nbytes) {
p = NULL;
prop_limit = 0;
} else {
p = ((char *)outp) + nbytes;
prop_limit = limit - nbytes;
}
name = bhnd_nvram_prop_name(prop);
name_len = strlen(name) + 1;
if (prop_limit > name_len) {
memcpy(p, name, name_len - 1);
p[name_len - 1] = '=';
prop_limit -= name_len;
p += name_len;
} else {
prop_limit = 0;
p = NULL;
}
if (SIZE_MAX - nbytes < name_len)
return (EFTYPE);
nbytes += name_len;
value_len = prop_limit;
error = bhnd_nvram_prop_encode(prop, p, &value_len,
BHND_NVRAM_TYPE_STRING);
if (error && error != ENOMEM) {
BHND_NV_LOG("error serializing %s to required type "
"%s: %d\n", name,
bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
error);
return (error);
}
if (SIZE_MAX - nbytes < value_len)
return (EFTYPE);
nbytes += value_len;
}
if (limit > nbytes)
*((char *)outp + nbytes) = '\0';
if (nbytes == SIZE_MAX)
return (EFTYPE);
else
nbytes++;
if (nbytes <= UINT32_MAX) {
hdr.size = (uint32_t)nbytes;
} else {
BHND_NV_LOG("size %zu exceeds maximum supported size of %u "
"bytes\n", nbytes, UINT32_MAX);
return (EFTYPE);
}
*olen = nbytes;
if (limit < *olen) {
if (outp == NULL)
return (0);
return (ENOMEM);
}
BHND_NV_ASSERT(nbytes >= BCM_NVRAM_CRC_SKIP, ("invalid output size"));
crc8 = bhnd_nvram_crc8((uint8_t *)outp + BCM_NVRAM_CRC_SKIP,
nbytes - BCM_NVRAM_CRC_SKIP, BHND_NVRAM_CRC8_INITIAL);
BHND_NV_ASSERT(nbytes >= sizeof(hdr), ("invalid output size"));
hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_CRC, crc8);
memcpy(outp, &hdr, sizeof(hdr));
return (0);
}
static int
bhnd_nvram_bcm_init(struct bhnd_nvram_bcm *bcm, struct bhnd_nvram_io *src)
{
struct bhnd_nvram_bcmhdr hdr;
uint8_t *p;
void *ptr;
size_t io_offset, io_size;
uint8_t crc, valid, bcm_ver;
int error;
if ((error = bhnd_nvram_io_read(src, 0x0, &hdr, sizeof(hdr))))
return (error);
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
return (ENXIO);
io_size = le32toh(hdr.size);
if (io_size < sizeof(hdr)) {
BHND_NV_LOG("corrupt header size: %zu\n", io_size);
return (EINVAL);
}
if (io_size > bhnd_nvram_io_getsize(src)) {
BHND_NV_LOG("header size %zu exceeds input size %zu\n",
io_size, bhnd_nvram_io_getsize(src));
return (EINVAL);
}
if (io_size == SIZE_MAX)
return (ENOMEM);
bcm->data = bhnd_nvram_iobuf_empty(io_size, io_size + 1);
if (bcm->data == NULL)
return (ENOMEM);
error = bhnd_nvram_io_write_ptr(bcm->data, 0x0, &ptr, io_size, NULL);
if (error)
return (error);
p = ptr;
if ((error = bhnd_nvram_io_read(src, 0x0, p, io_size)))
return (error);
valid = BCM_NVRAM_GET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_CRC);
crc = bhnd_nvram_crc8(p + BCM_NVRAM_CRC_SKIP,
io_size - BCM_NVRAM_CRC_SKIP, BHND_NVRAM_CRC8_INITIAL);
if (crc != valid) {
BHND_NV_LOG("warning: NVRAM CRC error (crc=%#hhx, "
"expected=%hhx)\n", crc, valid);
}
#define BCM_READ_HDR_VAR(_name, _dest, _swap) do { \
struct bhnd_nvram_bcm_hvar *data; \
data = bhnd_nvram_bcm_gethdrvar(bcm, _name ##_VAR); \
BHND_NV_ASSERT(data != NULL, \
("no such header variable: " __STRING(_name))); \
\
\
data->value. _dest = _swap(BCM_NVRAM_GET_BITS( \
hdr. _name ## _FIELD, _name)); \
} while(0)
BCM_READ_HDR_VAR(BCM_NVRAM_CFG0_SDRAM_INIT, u16, le16toh);
BCM_READ_HDR_VAR(BCM_NVRAM_CFG1_SDRAM_CFG, u16, le16toh);
BCM_READ_HDR_VAR(BCM_NVRAM_CFG1_SDRAM_REFRESH, u16, le16toh);
BCM_READ_HDR_VAR(BCM_NVRAM_SDRAM_NCDL, u32, le32toh);
_Static_assert(nitems(bcm->hvars) == 4, "missing initialization for"
"NVRAM header variable(s)");
#undef BCM_READ_HDR_VAR
bcm->count = 0;
io_offset = sizeof(hdr);
while (io_offset < io_size) {
char *envp;
const char *name, *value;
size_t envp_len;
size_t name_len, value_len;
envp = (char *) (p + io_offset);
envp_len = strnlen(envp, io_size - io_offset);
error = bhnd_nvram_parse_env(envp, envp_len, '=', &name,
&name_len, &value, &value_len);
if (error) {
BHND_NV_LOG("error parsing envp at offset %#zx: %d\n",
io_offset, error);
return (error);
}
*(envp + name_len) = '\0';
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
struct bhnd_nvram_bcm_hvar *hvar;
union bhnd_nvram_bcm_hvar_value hval;
size_t hval_len;
hvar = &bcm->hvars[i];
if (hvar->envp != NULL)
continue;
if ((strcmp(name, hvar->name)) != 0)
continue;
hvar->envp = envp;
hval_len = sizeof(hval);
error = bhnd_nvram_value_coerce(value, value_len,
BHND_NVRAM_TYPE_STRING, &hval, &hval_len,
hvar->type);
if (error) {
BHND_NV_LOG("error parsing header variable "
"'%s=%s': %d\n", name, value, error);
} else if (hval_len != hvar->len) {
hvar->stale = true;
} else if (memcmp(&hval, &hvar->value, hval_len) != 0) {
hvar->stale = true;
}
}
io_offset += envp_len;
if (io_offset == io_size) {
BHND_NV_LOG("missing terminating NUL at offset %#zx\n",
io_offset);
return (EINVAL);
}
if (*(p + io_offset) != '\0') {
BHND_NV_LOG("invalid terminator '%#hhx' at offset "
"%#zx\n", *(p + io_offset), io_offset);
return (EINVAL);
}
bcm->count++;
if (++io_offset == io_size) {
char ch;
io_size++;
if ((error = bhnd_nvram_io_setsize(bcm->data, io_size)))
return (error);
ch = '\0';
error = bhnd_nvram_io_write(bcm->data, io_size-1, &ch,
sizeof(ch));
if (error)
return (error);
}
if (*(p + io_offset) == '\0')
break;
}
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
if (bcm->hvars[i].envp == NULL)
bcm->count++;
}
bcm_ver = BCM_NVRAM_GET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_VER);
error = bhnd_nvram_plist_append_bytes(bcm->opts,
BCM_NVRAM_ENCODE_OPT_VERSION, &bcm_ver, sizeof(bcm_ver),
BHND_NVRAM_TYPE_UINT8);
if (error)
return (error);
return (0);
}
static int
bhnd_nvram_bcm_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
{
struct bhnd_nvram_bcm *bcm;
int error;
bcm = (struct bhnd_nvram_bcm *)nv;
_Static_assert(sizeof(bcm->hvars) == sizeof(bhnd_nvram_bcm_hvars),
"hvar declarations must match bhnd_nvram_bcm_hvars template");
memcpy(bcm->hvars, bhnd_nvram_bcm_hvars, sizeof(bcm->hvars));
bcm->opts = bhnd_nvram_plist_new();
if (bcm->opts == NULL)
return (ENOMEM);
if ((error = bhnd_nvram_bcm_init(bcm, io))) {
bhnd_nvram_bcm_free(nv);
return (error);
}
return (0);
}
static void
bhnd_nvram_bcm_free(struct bhnd_nvram_data *nv)
{
struct bhnd_nvram_bcm *bcm = (struct bhnd_nvram_bcm *)nv;
if (bcm->data != NULL)
bhnd_nvram_io_free(bcm->data);
if (bcm->opts != NULL)
bhnd_nvram_plist_release(bcm->opts);
}
size_t
bhnd_nvram_bcm_count(struct bhnd_nvram_data *nv)
{
struct bhnd_nvram_bcm *bcm = (struct bhnd_nvram_bcm *)nv;
return (bcm->count);
}
static bhnd_nvram_plist *
bhnd_nvram_bcm_options(struct bhnd_nvram_data *nv)
{
struct bhnd_nvram_bcm *bcm = (struct bhnd_nvram_bcm *)nv;
return (bcm->opts);
}
static uint32_t
bhnd_nvram_bcm_caps(struct bhnd_nvram_data *nv)
{
return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
}
static const char *
bhnd_nvram_bcm_next(struct bhnd_nvram_data *nv, void **cookiep)
{
struct bhnd_nvram_bcm *bcm;
struct bhnd_nvram_bcm_hvar *hvar, *hvar_next;
const void *ptr;
const char *envp, *basep;
size_t io_size, io_offset;
int error;
bcm = (struct bhnd_nvram_bcm *)nv;
io_offset = sizeof(struct bhnd_nvram_bcmhdr);
io_size = bhnd_nvram_io_getsize(bcm->data) - io_offset;
error = bhnd_nvram_io_read_ptr(bcm->data, io_offset, &ptr, io_size,
NULL);
if (error) {
BHND_NV_LOG("error mapping backing buffer: %d\n", error);
return (NULL);
}
basep = ptr;
hvar = bhnd_nvram_bcm_to_hdrvar(bcm, *cookiep);
if (hvar != NULL) {
size_t idx;
idx = bhnd_nvram_bcm_hdrvar_index(bcm, hvar) + 1;
for (size_t i = idx; i < nitems(bcm->hvars); i++) {
hvar_next = &bcm->hvars[i];
if (hvar_next->envp != NULL && !hvar_next->stale)
continue;
*cookiep = hvar_next;
return (hvar_next->name);
}
return (NULL);
}
if (*cookiep == NULL) {
envp = basep;
} else {
envp = *cookiep;
envp += strlen(envp) + 1;
envp += strlen(envp) + 1;
}
while ((size_t)(envp - basep) < io_size && *envp != '\0') {
hvar = NULL;
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
if (bcm->hvars[i].envp != envp)
continue;
hvar = &bcm->hvars[i];
break;
}
if (hvar == NULL || !hvar->stale)
break;
envp += strlen(envp) + 1;
envp += strlen(envp) + 1;
}
if ((size_t)(envp - basep) == io_size || *envp == '\0') {
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
if (bcm->hvars[i].envp != NULL)
continue;
*cookiep = &bcm->hvars[i];
return (bcm->hvars[i].name);
}
return (NULL);
}
*cookiep = __DECONST(void *, envp);
return (envp);
}
static void *
bhnd_nvram_bcm_find(struct bhnd_nvram_data *nv, const char *name)
{
return (bhnd_nvram_data_generic_find(nv, name));
}
static int
bhnd_nvram_bcm_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
void *cookiep2)
{
struct bhnd_nvram_bcm *bcm;
struct bhnd_nvram_bcm_hvar *hvar1, *hvar2;
bcm = (struct bhnd_nvram_bcm *)nv;
hvar1 = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep1);
hvar2 = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep2);
if (hvar1 != NULL && hvar2 == NULL) {
return (1);
} else if (hvar1 == NULL && hvar2 != NULL) {
return (-1);
}
if (cookiep1 < cookiep2)
return (-1);
if (cookiep1 > cookiep2)
return (1);
return (0);
}
static int
bhnd_nvram_bcm_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
size_t *len, bhnd_nvram_type type)
{
return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
}
static int
bhnd_nvram_bcm_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
bhnd_nvram_val **value)
{
return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
}
static const void *
bhnd_nvram_bcm_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
size_t *len, bhnd_nvram_type *type)
{
struct bhnd_nvram_bcm *bcm;
struct bhnd_nvram_bcm_hvar *hvar;
const char *envp;
bcm = (struct bhnd_nvram_bcm *)nv;
if ((hvar = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep)) != NULL) {
BHND_NV_ASSERT(bhnd_nvram_value_check_aligned(&hvar->value,
hvar->len, hvar->type) == 0, ("value misaligned"));
*type = hvar->type;
*len = hvar->len;
return (&hvar->value);
}
BHND_NV_ASSERT(cookiep != NULL, ("NULL cookiep"));
envp = cookiep;
envp += strlen(envp) + 1;
*len = strlen(envp) + 1;
*type = BHND_NVRAM_TYPE_STRING;
return (envp);
}
static const char *
bhnd_nvram_bcm_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
{
struct bhnd_nvram_bcm *bcm;
struct bhnd_nvram_bcm_hvar *hvar;
bcm = (struct bhnd_nvram_bcm *)nv;
if ((hvar = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep)) != NULL) {
return (hvar->name);
}
return (cookiep);
}
static int
bhnd_nvram_bcm_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
bhnd_nvram_val *value, bhnd_nvram_val **result)
{
bhnd_nvram_val *str;
int error;
if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
return (EINVAL);
error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
value, BHND_NVRAM_VAL_DYNAMIC);
if (error)
return (error);
*result = str;
return (0);
}
static int
bhnd_nvram_bcm_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
{
return (0);
}
static struct bhnd_nvram_bcm_hvar *
bhnd_nvram_bcm_gethdrvar(struct bhnd_nvram_bcm *bcm, const char *name)
{
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
if (strcmp(bcm->hvars[i].name, name) == 0)
return (&bcm->hvars[i]);
}
return (NULL);
}
static struct bhnd_nvram_bcm_hvar *
bhnd_nvram_bcm_to_hdrvar(struct bhnd_nvram_bcm *bcm, void *cookiep)
{
#ifdef BHND_NVRAM_INVARIANTS
uintptr_t base, ptr;
#endif
if (nitems(bcm->hvars) == 0)
return (NULL);
if (cookiep < (void *)&bcm->hvars[0])
return (NULL);
if (cookiep > (void *)&bcm->hvars[nitems(bcm->hvars)-1])
return (NULL);
#ifdef BHND_NVRAM_INVARIANTS
base = (uintptr_t)bcm->hvars;
ptr = (uintptr_t)cookiep;
BHND_NV_ASSERT((ptr - base) % sizeof(bcm->hvars[0]) == 0,
("misaligned hvar pointer %p/%p", cookiep, bcm->hvars));
#endif
return ((struct bhnd_nvram_bcm_hvar *)cookiep);
}
static size_t
bhnd_nvram_bcm_hdrvar_index(struct bhnd_nvram_bcm *bcm,
struct bhnd_nvram_bcm_hvar *hdrvar)
{
BHND_NV_ASSERT(bhnd_nvram_bcm_to_hdrvar(bcm, (void *)hdrvar) != NULL,
("%p is not a valid hdrvar reference", hdrvar));
return (hdrvar - &bcm->hvars[0]);
}