Page MenuHomeFreeBSD

D9913.id26043.diff
No OneTemporary

D9913.id26043.diff

Index: sys/dev/bhnd/nvram/bhnd_nvram_data.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data.h
+++ sys/dev/bhnd/nvram/bhnd_nvram_data.h
@@ -105,6 +105,11 @@
bhnd_nvram_data_class *classes[],
size_t num_classes);
+int bhnd_nvram_data_getvar_direct(
+ bhnd_nvram_data_class *cls,
+ struct bhnd_nvram_io *io, const char *name,
+ void *buf, size_t *len, bhnd_nvram_type type);
+
int bhnd_nvram_data_new(bhnd_nvram_data_class *cls,
struct bhnd_nvram_data **nv,
struct bhnd_nvram_io *io);
Index: sys/dev/bhnd/nvram/bhnd_nvram_data.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data.c
@@ -228,6 +228,41 @@
}
/**
+ * Read a variable directly from @p io and decode as @p type.
+ *
+ * This may be used to perform reading of NVRAM variables during the very
+ * early boot process, prior to the availability of the kernel allocator.
+ *
+ * @param cls An NVRAM class capable of parsing @p io.
+ * @param io NVRAM data to be parsed.
+ * @param name The raw name of the variable to be fetched,
+ * including any device path (/pci/1/1/varname) or
+ * alias prefix (0:varname).
+ * @param[out] buf On success, the requested value will be written
+ * to this buffer. This argment may be NULL if
+ * the value is not desired.
+ * @param[in,out] len The capacity of @p buf. On success, will be set
+ * to the actual size of the requested value.
+ * @param type The data type to be written to @p buf.
+ *
+ * @retval 0 success
+ * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
+ * small to hold the requested value.
+ * @retval ENOENT If @p name is not found in @p io.
+ * @retval EFTYPE If the variable data cannot be coerced to @p type.
+ * @retval ERANGE If value coercion would overflow @p type.
+ * @retval non-zero If parsing @p io otherwise fails, a regular unix error
+ * code will be returned.
+ */
+int
+bhnd_nvram_data_getvar_direct(bhnd_nvram_data_class *cls,
+ struct bhnd_nvram_io *io, const char *name, void *buf, size_t *len,
+ bhnd_nvram_type type)
+{
+ return (cls->op_getvar_direct(io, name, buf, len, type));
+}
+
+/**
* Allocate and initialize a new instance of data class @p cls, copying and
* parsing NVRAM data from @p io.
*
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
@@ -144,9 +144,229 @@
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);
}
+/**
+ * Parser states for bhnd_nvram_bcm_getvar_direct_common().
+ */
+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));
+}
+
+/**
+ * Common BCM/BCMRAW implementation of bhnd_nvram_getvar_direct().
+ */
+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;
+
+ /* Fetch and validate the header */
+ 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);
+ }
+
+ /* Loop our parser until we find the requested variable, or hit EOF */
+ 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)));
+
+ /* Repopulate our parse buffer? */
+ 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!"));
+
+ /* An extra '\0' denotes NVRAM EOF */
+ if (buf[bufpos] == '\0')
+ return (ENOENT);
+
+ /* Reset name matching position */
+ namepos = 0;
+
+ /* Start name matching */
+ 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) {
+ /* Matched */
+ namepos += navail;
+ bufpos += navail;
+
+ /* If we've matched the full variable name,
+ * look for its trailing delimiter */
+ if (namepos == namelen)
+ pstate = BCM_PARSE_KEY;
+ } else {
+ /* No match; advance to next entry and restart
+ * name matching */
+ pstate = BCM_PARSE_NEXT_KEY;
+ }
+
+ break;
+ }
+
+ case BCM_PARSE_KEY:
+ BHND_NV_ASSERT(buflen - bufpos > 0, ("empty buffer!"));
+
+ if (buf[bufpos] == '=') {
+ /* Key fully matched; advance past '=' and
+ * parse the value */
+ bufpos++;
+ pstate = BCM_PARSE_VALUE_START;
+ } else {
+ /* No match; advance to next entry and restart
+ * name matching */
+ pstate = BCM_PARSE_NEXT_KEY;
+ }
+
+ break;
+
+ case BCM_PARSE_NEXT_KEY: {
+ const char *p;
+
+ /* Scan for a '\0' terminator */
+ p = memchr(buf+bufpos, '\0', buflen - bufpos);
+
+ if (p != NULL) {
+ /* Found entry terminator; restart name
+ * matching at next entry */
+ pstate = BCM_PARSE_KEY_START;
+ bufpos = (p - buf) + 1 /* skip '\0' */;
+ } else {
+ /* Consumed full buffer looking for '\0';
+ * force repopulation of the buffer and
+ * retry */
+ bufpos = buflen;
+ }
+
+ break;
+ }
+
+ case BCM_PARSE_VALUE_START: {
+ const char *p;
+
+ /* Scan for a '\0' terminator */
+ p = memchr(buf+bufpos, '\0', buflen - bufpos);
+
+ if (p != NULL) {
+ /* Found entry terminator; parse the value */
+ vlen = p - &buf[bufpos];
+ pstate = BCM_PARSE_VALUE;
+
+ } else if (p == NULL && offset == limit) {
+ /* Hit EOF without a terminating '\0';
+ * treat the entry as implicitly terminated */
+ vlen = buflen - bufpos;
+ pstate = BCM_PARSE_VALUE;
+
+ } else if (p == NULL && bufpos > 0) {
+ size_t nread;
+
+ /* Move existing value data to start of
+ * buffer */
+ memmove(buf, buf+bufpos, buflen - bufpos);
+ buflen = bufpos;
+ bufpos = 0;
+
+ /* Populate full buffer to allow retry of
+ * value parsing */
+ 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 {
+ /* Value exceeds our buffer capacity */
+ 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));
+ }
+ }
+
+ /* Variable not found */
+ 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)
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
@@ -50,6 +50,7 @@
#include "bhnd_nvram_private.h"
#include "bhnd_nvram_datavar.h"
+#include "bhnd_nvram_data_bcmvar.h"
/*
* Broadcom-RAW NVRAM data class.
@@ -133,6 +134,14 @@
}
static int
+bhnd_nvram_bcmraw_getvar_direct(struct bhnd_nvram_io *io, const char *name,
+ void *buf, size_t *len, bhnd_nvram_type type)
+{
+ return (bhnd_nvram_bcm_getvar_direct_common(io, name, buf, len, type,
+ false));
+}
+
+static int
bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
bhnd_nvram_plist *options, void *outp, size_t *olen)
{
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_bcmvar.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_bcmvar.h
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_bcmvar.h
@@ -69,4 +69,8 @@
uint32_t sdram_ncdl; /**< sdram_ncdl */
} __packed;
+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);
+
#endif /* _BHND_NVRAM_BHND_NVRAM_BCMVAR_H_ */
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
@@ -124,6 +124,226 @@
return (BHND_NVRAM_DATA_PROBE_MAYBE);
}
+
+/**
+ * Parser states for bhnd_nvram_bcm_getvar_direct_common().
+ */
+typedef enum {
+ BTXT_PARSE_LINE_START,
+ BTXT_PARSE_KEY,
+ BTXT_PARSE_KEY_END,
+ BTXT_PARSE_NEXT_LINE,
+ BTXT_PARSE_VALUE_START,
+ BTXT_PARSE_VALUE
+} btxt_parse_state;
+
+static int
+bhnd_nvram_btxt_getvar_direct(struct bhnd_nvram_io *io, const char *name,
+ void *outp, size_t *olen, bhnd_nvram_type otype)
+{
+ char buf[512];
+ btxt_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;
+
+ /* Loop our parser until we find the requested variable, or hit EOF */
+ pstate = BTXT_PARSE_LINE_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)));
+
+ /* Repopulate our parse buffer? */
+ 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 BTXT_PARSE_LINE_START:
+ BHND_NV_ASSERT(bufpos < buflen, ("empty buffer!"));
+
+ /* Reset name matching position */
+ namepos = 0;
+
+ /* Trim any leading whitespace */
+ while (bufpos < buflen && bhnd_nv_isspace(buf[bufpos]))
+ {
+ bufpos++;
+ }
+
+ if (bufpos == buflen) {
+ /* Continue parsing the line */
+ pstate = BTXT_PARSE_LINE_START;
+ } else if (bufpos < buflen && buf[bufpos] == '#') {
+ /* Comment; skip to next line */
+ pstate = BTXT_PARSE_NEXT_LINE;
+ } else {
+ /* Start name matching */
+ pstate = BTXT_PARSE_KEY;
+ }
+
+
+ break;
+
+ case BTXT_PARSE_KEY: {
+ size_t navail, nleft;
+
+ nleft = namelen - namepos;
+ navail = bhnd_nv_ummin(buflen - bufpos, nleft);
+
+ if (strncmp(name+namepos, buf+bufpos, navail) == 0) {
+ /* Matched */
+ namepos += navail;
+ bufpos += navail;
+
+ if (namepos == namelen) {
+ /* Matched the full variable; look for
+ * its trailing delimiter */
+ pstate = BTXT_PARSE_KEY_END;
+ } else {
+ /* Continue matching the name */
+ pstate = BTXT_PARSE_KEY;
+ }
+ } else {
+ /* No match; advance to next entry and restart
+ * name matching */
+ pstate = BTXT_PARSE_NEXT_LINE;
+ }
+
+ break;
+ }
+
+ case BTXT_PARSE_KEY_END:
+ BHND_NV_ASSERT(bufpos < buflen, ("empty buffer!"));
+
+ if (buf[bufpos] == '=') {
+ /* Key fully matched; advance past '=' and
+ * parse the value */
+ bufpos++;
+ pstate = BTXT_PARSE_VALUE_START;
+ } else {
+ /* No match; advance to next line and restart
+ * name matching */
+ pstate = BTXT_PARSE_NEXT_LINE;
+ }
+
+ break;
+
+ case BTXT_PARSE_NEXT_LINE: {
+ const char *p;
+
+ /* Scan for a '\r', '\n', or '\r\n' terminator */
+ p = memchr(buf+bufpos, '\n', buflen - bufpos);
+ if (p == NULL)
+ p = memchr(buf+bufpos, '\r', buflen - bufpos);
+
+ if (p != NULL) {
+ /* Found entry terminator; restart name
+ * matching at next line */
+ pstate = BTXT_PARSE_LINE_START;
+ bufpos = (p - buf);
+ } else {
+ /* Consumed full buffer looking for newline;
+ * force repopulation of the buffer and
+ * retry */
+ pstate = BTXT_PARSE_NEXT_LINE;
+ bufpos = buflen;
+ }
+
+ break;
+ }
+
+ case BTXT_PARSE_VALUE_START: {
+ const char *p;
+
+ /* Scan for a terminating newline */
+ p = memchr(buf+bufpos, '\n', buflen - bufpos);
+ if (p == NULL)
+ p = memchr(buf+bufpos, '\r', buflen - bufpos);
+
+ if (p != NULL) {
+ /* Found entry terminator; parse the value */
+ vlen = p - &buf[bufpos];
+ pstate = BTXT_PARSE_VALUE;
+
+ } else if (p == NULL && offset == limit) {
+ /* Hit EOF without a terminating newline;
+ * treat the entry as implicitly terminated */
+ vlen = buflen - bufpos;
+ pstate = BTXT_PARSE_VALUE;
+
+ } else if (p == NULL && bufpos > 0) {
+ size_t nread;
+
+ /* Move existing value data to start of
+ * buffer */
+ memmove(buf, buf+bufpos, buflen - bufpos);
+ buflen = bufpos;
+ bufpos = 0;
+
+ /* Populate full buffer to allow retry of
+ * value parsing */
+ 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 {
+ /* Value exceeds our buffer capacity */
+ BHND_NV_LOG("cannot parse value for '%s' "
+ "(exceeds %zu byte limit)\n", name,
+ sizeof(buf));
+
+ return (ENXIO);
+ }
+
+ break;
+ }
+
+ case BTXT_PARSE_VALUE:
+ BHND_NV_ASSERT(vlen <= buflen, ("value buf overrun"));
+
+ /* Trim any trailing whitespace */
+ while (vlen > 0 && bhnd_nv_isspace(buf[bufpos+vlen-1]))
+ vlen--;
+
+ /* Write the value to the caller's buffer */
+ return (bhnd_nvram_value_coerce(buf+bufpos, vlen,
+ BHND_NVRAM_TYPE_STRING, outp, olen, otype));
+ }
+ }
+
+ /* Variable not found */
+ return (ENOENT);
+}
+
static int
bhnd_nvram_btxt_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
bhnd_nvram_plist *options, void *outp, size_t *olen)
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
@@ -68,8 +68,7 @@
static int bhnd_nvram_sprom_ident(
struct bhnd_nvram_io *io,
- const bhnd_sprom_layout **ident,
- struct bhnd_nvram_io **shadow);
+ const bhnd_sprom_layout **ident);
static int bhnd_nvram_sprom_write_var(
bhnd_sprom_opcode_state *state,
@@ -77,6 +76,13 @@
bhnd_nvram_val *value,
struct bhnd_nvram_io *io);
+static int bhnd_nvram_sprom_read_var(
+ struct bhnd_sprom_opcode_state *state,
+ struct bhnd_sprom_opcode_idx_entry *entry,
+ struct bhnd_nvram_io *io,
+ union bhnd_nvram_sprom_storage *storage,
+ bhnd_nvram_val *val);
+
static int bhnd_nvram_sprom_write_offset(
const struct bhnd_nvram_vardefn *var,
struct bhnd_nvram_io *data,
@@ -153,10 +159,6 @@
*
* @param io An I/O context mapping the SPROM data to be identified.
* @param[out] ident On success, the identified SPROM layout.
- * @param[out] shadow On success, a correctly sized iobuf instance mapping
- * a copy of the identified SPROM image. The caller is
- * responsible for deallocating this instance via
- * bhnd_nvram_io_free()
*
* @retval 0 success
* @retval non-zero If identifying @p io otherwise fails, a regular unix
@@ -164,77 +166,69 @@
*/
static int
bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io,
- const bhnd_sprom_layout **ident, struct bhnd_nvram_io **shadow)
+ const bhnd_sprom_layout **ident)
{
- struct bhnd_nvram_io *buf;
- uint8_t crc;
- size_t crc_errors;
- size_t sprom_sz_max;
- int error;
+ uint8_t crc;
+ size_t crc_errors;
+ size_t nbytes;
+ int error;
- /* Find the largest SPROM layout size */
- sprom_sz_max = 0;
- for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) {
- sprom_sz_max = bhnd_nv_ummax(sprom_sz_max,
- bhnd_sprom_layouts[i].size);
- }
-
- /* Allocate backing buffer and initialize CRC state */
- buf = bhnd_nvram_iobuf_empty(0, sprom_sz_max);
crc = BHND_NVRAM_CRC8_INITIAL;
crc_errors = 0;
+ nbytes = 0;
/* We iterate the SPROM layouts smallest to largest, allowing us to
* perform incremental checksum calculation */
for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) {
const bhnd_sprom_layout *layout;
- void *ptr;
- size_t nbytes, nr;
+ u_char buf[512];
+ size_t nread;
uint16_t magic;
uint8_t srev;
bool crc_valid;
bool have_magic;
layout = &bhnd_sprom_layouts[i];
- nbytes = bhnd_nvram_io_getsize(buf);
- if ((layout->flags & SPROM_LAYOUT_MAGIC_NONE)) {
+ have_magic = true;
+ if ((layout->flags & SPROM_LAYOUT_MAGIC_NONE))
have_magic = false;
- } else {
- have_magic = true;
- }
- /* Layout instances must be ordered from smallest to largest by
- * the nvram_map compiler */
+ /*
+ * Read image data and update CRC (errors are reported
+ * after the signature check)
+ *
+ * Layout instances must be ordered from smallest to largest by
+ * the nvram_map compiler, allowing us to incrementally update
+ * our CRC.
+ */
if (nbytes > layout->size)
- BHND_NV_PANIC("SPROM layout is defined out-of-order");
+ BHND_NV_PANIC("SPROM layout defined out-of-order");
- /* Calculate number of additional bytes to be read */
- nr = layout->size - nbytes;
+ nread = layout->size - nbytes;
- /* Adjust the buffer size and fetch a write pointer */
- if ((error = bhnd_nvram_io_setsize(buf, layout->size)))
- goto failed;
+ while (nread > 0) {
+ size_t nr;
- error = bhnd_nvram_io_write_ptr(buf, nbytes, &ptr, nr, NULL);
- if (error)
- goto failed;
+ nr = bhnd_nv_ummin(nread, sizeof(buf));
+
+ if ((error = bhnd_nvram_io_read(io, nbytes, buf, nr)))
+ return (error);
- /* Read image data and update CRC (errors are reported
- * after the signature check) */
- if ((error = bhnd_nvram_io_read(io, nbytes, ptr, nr)))
- goto failed;
+ crc = bhnd_nvram_crc8(buf, nr, crc);
+ crc_valid = (crc == BHND_NVRAM_CRC8_VALID);
+ if (!crc_valid)
+ crc_errors++;
- crc = bhnd_nvram_crc8(ptr, nr, crc);
- crc_valid = (crc == BHND_NVRAM_CRC8_VALID);
- if (!crc_valid)
- crc_errors++;
+ nread -= nr;
+ nbytes += nr;
+ }
- /* Fetch SPROM revision */
- error = bhnd_nvram_io_read(buf, layout->srev_offset, &srev,
+ /* Read SPROM revision */
+ error = bhnd_nvram_io_read(io, layout->srev_offset, &srev,
sizeof(srev));
if (error)
- goto failed;
+ return (error);
/* Early sromrev 1 devices (specifically some BCM440x enet
* cards) are reported to have been incorrectly programmed
@@ -248,7 +242,7 @@
/* Check the magic value, skipping to the next layout on
* failure. */
- error = bhnd_nvram_sprom_check_magic(buf, layout, &magic);
+ error = bhnd_nvram_sprom_check_magic(io, layout, &magic);
if (error) {
/* If the CRC is was valid, log the mismatch */
if (crc_valid || BHND_NV_VERBOSE) {
@@ -256,8 +250,7 @@
"0x%hx (expected 0x%hx)\n", srev,
magic, layout->magic_value);
- error = ENXIO;
- goto failed;
+ return (ENXIO);
}
continue;
@@ -277,40 +270,93 @@
}
/* Identified */
- *shadow = buf;
*ident = layout;
return (0);
}
- /* No match -- set error and fallthrough */
- error = ENXIO;
+ /* No match */
if (crc_errors > 0 && BHND_NV_VERBOSE) {
BHND_NV_LOG("sprom parsing failed with %zu CRC errors\n",
crc_errors);
}
-failed:
- bhnd_nvram_io_free(buf);
- return (error);
+ return (ENXIO);
}
static int
bhnd_nvram_sprom_probe(struct bhnd_nvram_io *io)
{
const bhnd_sprom_layout *layout;
- struct bhnd_nvram_io *shadow;
int error;
/* Try to parse the input */
- if ((error = bhnd_nvram_sprom_ident(io, &layout, &shadow)))
+ if ((error = bhnd_nvram_sprom_ident(io, &layout)))
return (error);
- /* Clean up the shadow iobuf */
- bhnd_nvram_io_free(shadow);
-
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
}
+static int
+bhnd_nvram_sprom_getvar_direct(struct bhnd_nvram_io *io, const char *name,
+ void *buf, size_t *len, bhnd_nvram_type type)
+{
+ const bhnd_sprom_layout *layout;
+ bhnd_sprom_opcode_state state;
+ const struct bhnd_nvram_vardefn *var;
+ size_t vid;
+ int error;
+
+ /* Look up the variable definition and ID */
+ if ((var = bhnd_nvram_find_vardefn(name)) == NULL)
+ return (ENOENT);
+
+ vid = bhnd_nvram_get_vardefn_id(var);
+
+ /* Identify the SPROM image layout */
+ if ((error = bhnd_nvram_sprom_ident(io, &layout)))
+ return (error);
+
+ /* Initialize SPROM layout interpreter */
+ if ((error = bhnd_sprom_opcode_init(&state, layout))) {
+ BHND_NV_LOG("error initializing opcode state: %d\n", error);
+ return (ENXIO);
+ }
+
+ /* Find SPROM layout entry for the requested variable */
+ while ((error = bhnd_sprom_opcode_next_var(&state)) == 0) {
+ bhnd_sprom_opcode_idx_entry entry;
+ union bhnd_nvram_sprom_storage storage;
+ bhnd_nvram_val val;
+
+ /* Fetch the variable's entry state */
+ if ((error = bhnd_sprom_opcode_init_entry(&state, &entry)))
+ return (error);
+
+ /* Match against expected VID */
+ if (entry.vid != vid)
+ continue;
+
+ /* Decode variable to a new value instance */
+ error = bhnd_nvram_sprom_read_var(&state, &entry, io, &storage,
+ &val);
+ if (error)
+ return (error);
+
+ /* Perform value coercion */
+ error = bhnd_nvram_val_encode(&val, buf, len, type);
+
+ /* Clean up */
+ bhnd_nvram_val_release(&val);
+ return (error);
+ }
+
+ /* Hit EOF without matching the requested variable? */
+ if (error == ENOENT)
+ return (ENOENT);
+
+ /* Some other parse error occured */
+ return (error);
+}
/**
* Return the SPROM layout definition for the given @p sromrev, or NULL if
@@ -365,7 +411,7 @@
var_base_type = bhnd_nvram_base_type(var->type);
/* Fetch the element count from the SPROM variable layout definition */
- if ((error = bhnd_sprom_opcode_parse_var(state, entry)))
+ if ((error = bhnd_sprom_opcode_eval_var(state, entry)))
return (error);
nelem = state->var.nelem;
@@ -717,7 +763,12 @@
sp = (struct bhnd_nvram_sprom *)nv;
/* Identify the SPROM input data */
- if ((error = bhnd_nvram_sprom_ident(io, &sp->layout, &sp->data)))
+ if ((error = bhnd_nvram_sprom_ident(io, &sp->layout)))
+ return (error);
+
+ /* Copy SPROM image to our shadow buffer */
+ sp->data = bhnd_nvram_iobuf_copy_range(io, 0, sp->layout->size);
+ if (sp->data == NULL)
goto failed;
/* Initialize SPROM binding eval state */
@@ -989,9 +1040,15 @@
}
/**
- * Common variable decoding; fetches and decodes variable to @p val,
- * using @p storage for actual data storage.
+ * Read a SPROM variable value from @p io.
*
+ * @param state The SPROM opcode state describing the layout of @p io.
+ * @param entry The variable's SPROM opcode index entry.
+ * @param io The input I/O context.
+ * @param storage Storage to be used with @p val.
+ * @param[out] val Value instance to be initialized with the
+ * parsed variable data.
+ *
* The returned @p val instance will hold a borrowed reference to @p storage,
* and must be copied via bhnd_nvram_val_copy() if it will be referenced beyond
* the lifetime of @p storage.
@@ -1000,13 +1057,12 @@
* via bhnd_nvram_val_release().
*/
static int
-bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
+bhnd_nvram_sprom_read_var(struct bhnd_sprom_opcode_state *state,
+ struct bhnd_sprom_opcode_idx_entry *entry, struct bhnd_nvram_io *io,
union bhnd_nvram_sprom_storage *storage, bhnd_nvram_val *val)
{
- struct bhnd_nvram_sprom *sp;
- bhnd_sprom_opcode_idx_entry *entry;
- const struct bhnd_nvram_vardefn *var;
union bhnd_nvram_sprom_storage *inp;
+ const struct bhnd_nvram_vardefn *var;
bhnd_nvram_type var_btype;
uint32_t intv;
size_t ilen, ipos, iwidth;
@@ -1014,14 +1070,9 @@
bool all_bits_set;
int error;
- sp = (struct bhnd_nvram_sprom *)nv;
- entry = cookiep;
-
- BHND_NV_ASSERT(cookiep != NULL, ("NULL variable cookiep"));
-
/* Fetch canonical variable definition */
- var = SPROM_COOKIE_TO_NVRAM_VAR(cookiep);
- BHND_NV_ASSERT(var != NULL, ("invalid cookiep %p", cookiep));
+ var = bhnd_nvram_get_vardefn(entry->vid);
+ BHND_NV_ASSERT(var != NULL, ("invalid entry"));
/*
* Fetch the array length from the SPROM variable definition.
@@ -1030,12 +1081,12 @@
* canonical NVRAM variable definition, but some SPROM layouts may
* define a smaller element count.
*/
- if ((error = bhnd_sprom_opcode_parse_var(&sp->state, entry))) {
+ if ((error = bhnd_sprom_opcode_eval_var(state, entry))) {
BHND_NV_LOG("variable evaluation failed: %d\n", error);
return (error);
}
- nelem = sp->state.var.nelem;
+ nelem = state->var.nelem;
if (nelem > var->nelem) {
BHND_NV_LOG("SPROM array element count %zu cannot be "
"represented by '%s' element count of %hhu\n", nelem,
@@ -1070,7 +1121,7 @@
/*
* Decode the SPROM data, iteratively decoding up to nelem values.
*/
- if ((error = bhnd_sprom_opcode_seek(&sp->state, entry))) {
+ if ((error = bhnd_sprom_opcode_seek(state, entry))) {
BHND_NV_LOG("variable seek failed: %d\n", error);
return (error);
}
@@ -1081,7 +1132,7 @@
all_bits_set = true;
else
all_bits_set = false;
- while ((error = bhnd_sprom_opcode_next_binding(&sp->state)) == 0) {
+ while ((error = bhnd_sprom_opcode_next_binding(state)) == 0) {
bhnd_sprom_opcode_bind *binding;
bhnd_sprom_opcode_var *binding_var;
bhnd_nvram_type intv_type;
@@ -1091,12 +1142,12 @@
void *ptr;
BHND_NV_ASSERT(
- sp->state.var_state >= SPROM_OPCODE_VAR_STATE_OPEN,
+ state->var_state >= SPROM_OPCODE_VAR_STATE_OPEN,
("invalid var state"));
- BHND_NV_ASSERT(sp->state.var.have_bind, ("invalid bind state"));
+ BHND_NV_ASSERT(state->var.have_bind, ("invalid bind state"));
- binding_var = &sp->state.var;
- binding = &sp->state.var.bind;
+ binding_var = &state->var;
+ binding = &state->var.bind;
if (ipos >= nelem) {
BHND_NV_LOG("output skip %u positioned "
@@ -1107,17 +1158,16 @@
/* Calculate input skip bytes for this binding */
skip_in_bytes = binding->skip_in;
- error = bhnd_sprom_opcode_apply_scale(&sp->state,
- &skip_in_bytes);
+ error = bhnd_sprom_opcode_apply_scale(state, &skip_in_bytes);
if (error)
return (error);
/* Bind */
- offset = sp->state.offset;
+ offset = state->offset;
for (size_t i = 0; i < binding->count; i++) {
/* Read the offset value, OR'ing with the current
* value of intv */
- error = bhnd_nvram_sprom_read_offset(var, sp->data,
+ error = bhnd_nvram_sprom_read_offset(var, io,
binding_var->base_type,
offset,
binding_var->mask,
@@ -1209,6 +1259,39 @@
return (error);
}
+
+/**
+ * Common variable decoding; fetches and decodes variable to @p val,
+ * using @p storage for actual data storage.
+ *
+ * The returned @p val instance will hold a borrowed reference to @p storage,
+ * and must be copied via bhnd_nvram_val_copy() if it will be referenced beyond
+ * the lifetime of @p storage.
+ *
+ * The caller is responsible for releasing any allocated value state
+ * via bhnd_nvram_val_release().
+ */
+static int
+bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
+ union bhnd_nvram_sprom_storage *storage, bhnd_nvram_val *val)
+{
+ struct bhnd_nvram_sprom *sp;
+ bhnd_sprom_opcode_idx_entry *entry;
+ const struct bhnd_nvram_vardefn *var;
+
+ BHND_NV_ASSERT(cookiep != NULL, ("NULL variable cookiep"));
+
+ sp = (struct bhnd_nvram_sprom *)nv;
+ entry = cookiep;
+
+ /* Fetch canonical variable definition */
+ var = SPROM_COOKIE_TO_NVRAM_VAR(cookiep);
+ BHND_NV_ASSERT(var != NULL, ("invalid cookiep %p", cookiep));
+
+ return (bhnd_nvram_sprom_read_var(&sp->state, entry, sp->data, storage,
+ val));
+}
+
static int
bhnd_nvram_sprom_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
void *cookiep2)
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
@@ -51,7 +51,6 @@
const void *rhs);
static int bhnd_sprom_opcode_reset(bhnd_sprom_opcode_state *state);
-static int bhnd_sprom_opcode_next_var(bhnd_sprom_opcode_state *state);
static int bhnd_sprom_opcode_set_type(bhnd_sprom_opcode_state *state,
bhnd_nvram_type type);
@@ -108,8 +107,6 @@
return (ENOMEM);
for (num_vars = 0; num_vars < num_idx; num_vars++) {
- size_t opcodes;
-
/* Seek to next entry */
if ((error = bhnd_sprom_opcode_next_var(state))) {
SPROM_OP_BAD(state, "error reading expected variable "
@@ -118,36 +115,14 @@
return (error);
}
- /* We limit the SPROM index representations to the minimal
- * type widths capable of covering all known layouts */
-
- /* Save SPROM image offset */
- if (state->offset > UINT16_MAX) {
- SPROM_OP_BAD(state, "cannot index large offset %u\n",
- state->offset);
- bhnd_nv_free(idx);
- return (ENXIO);
- }
- idx[num_vars].offset = state->offset;
-
- /* Save current variable ID */
- if (state->vid > UINT16_MAX) {
- SPROM_OP_BAD(state, "cannot index large vid %zu\n",
- state->vid);
- bhnd_nv_free(idx);
- return (ENXIO);
- }
- idx[num_vars].vid = state->vid;
-
- /* Save opcode position */
- opcodes = (state->input - state->layout->bindings);
- if (opcodes > UINT16_MAX) {
- SPROM_OP_BAD(state, "cannot index large opcode offset "
- "%zu\n", opcodes);
+ /* Record entry state in our index */
+ error = bhnd_sprom_opcode_init_entry(state, &idx[num_vars]);
+ if (error) {
+ SPROM_OP_BAD(state, "error initializing index for "
+ "entry: %d\n", error);
bhnd_nv_free(idx);
- return (ENXIO);
+ return (error);
}
- idx[num_vars].opcodes = opcodes;
}
/* Should have reached end of binding table; next read must return
@@ -314,6 +289,54 @@
return (&state->idx[idxpos]);
}
+
+/**
+ * Initialize @p entry with the current variable's opcode state.
+ *
+ * @param state The opcode state to be saved.
+ * @param[out] entry The opcode index entry to be initialized from @p state.
+ *
+ * @retval 0 success
+ * @retval ENXIO if @p state cannot be serialized as an index entry.
+ */
+int
+bhnd_sprom_opcode_init_entry(bhnd_sprom_opcode_state *state,
+ bhnd_sprom_opcode_idx_entry *entry)
+{
+ size_t opcodes;
+
+ /* We limit the SPROM index representations to the minimal type widths
+ * capable of covering all known layouts */
+
+ /* Save SPROM image offset */
+ if (state->offset > UINT16_MAX) {
+ SPROM_OP_BAD(state, "cannot index large offset %u\n",
+ state->offset);
+ return (ENXIO);
+ }
+
+ entry->offset = state->offset;
+
+ /* Save current variable ID */
+ if (state->vid > UINT16_MAX) {
+ SPROM_OP_BAD(state, "cannot index large vid %zu\n",
+ state->vid);
+ return (ENXIO);
+ }
+ entry->vid = state->vid;
+
+ /* Save opcode position */
+ opcodes = (state->input - state->layout->bindings);
+ if (opcodes > UINT16_MAX) {
+ SPROM_OP_BAD(state, "cannot index large opcode offset "
+ "%zu\n", opcodes);
+ return (ENXIO);
+ }
+ entry->opcodes = opcodes;
+
+ return (0);
+}
+
/**
* Reset SPROM opcode evaluation state and seek to the @p entry's position.
*
@@ -1255,7 +1278,7 @@
* returned.
*/
int
-bhnd_sprom_opcode_parse_var(bhnd_sprom_opcode_state *state,
+bhnd_sprom_opcode_eval_var(bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *entry)
{
uint8_t opcode;
@@ -1291,7 +1314,7 @@
* @retval non-zero if evaluation otherwise fails, a regular unix error
* code will be returned.
*/
-static int
+int
bhnd_sprom_opcode_next_var(bhnd_sprom_opcode_state *state)
{
uint8_t opcode;
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
@@ -64,13 +64,19 @@
bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *prev);
-int bhnd_sprom_opcode_parse_var(
+int bhnd_sprom_opcode_init_entry(
+ bhnd_sprom_opcode_state *state,
+ bhnd_sprom_opcode_idx_entry *entry);
+
+int bhnd_sprom_opcode_eval_var(
bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *entry);
int bhnd_sprom_opcode_seek(
bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *entry);
+int bhnd_sprom_opcode_next_var(
+ bhnd_sprom_opcode_state *state);
int bhnd_sprom_opcode_next_binding(
bhnd_sprom_opcode_state *state);
int bhnd_sprom_opcode_apply_scale(
Index: sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
+++ sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
@@ -165,6 +165,78 @@
}
static int
+bhnd_nvram_tlv_getvar_direct(struct bhnd_nvram_io *io, const char *name,
+ void *buf, size_t *len, bhnd_nvram_type type)
+{
+ struct bhnd_nvram_tlv_env env;
+ char data[NVRAM_TLV_ENVP_DATA_MAX_LEN];
+ size_t data_len;
+ const char *key, *value;
+ size_t keylen, vlen;
+ size_t namelen;
+ size_t next, off;
+ uint8_t tag;
+ int error;
+
+ namelen = strlen(name);
+
+ /* Iterate over the input looking for the requested variable */
+ next = 0;
+ while (!(error = bhnd_nvram_tlv_next_record(io, &next, &off, &tag))) {
+ switch (tag) {
+ case NVRAM_TLV_TYPE_END:
+ /* Not found */
+ return (ENOENT);
+
+ case NVRAM_TLV_TYPE_ENV:
+ /* Read the record header */
+ error = bhnd_nvram_io_read(io, off, &env, sizeof(env));
+ if (error) {
+ BHND_NV_LOG("error reading TLV_ENV record "
+ "header: %d\n", error);
+ return (error);
+ }
+
+ /* Read the record data */
+ data_len = NVRAM_TLV_ENVP_DATA_LEN(&env);
+ error = bhnd_nvram_io_read(io, off + sizeof(env), data,
+ data_len);
+ if (error) {
+ BHND_NV_LOG("error reading TLV_ENV record "
+ "data: %d\n", error);
+ return (error);
+ }
+
+ /* Parse the key=value string */
+ error = bhnd_nvram_parse_env(data, data_len, '=', &key,
+ &keylen, &value, &vlen);
+ if (error) {
+ BHND_NV_LOG("error parsing TLV_ENV data: %d\n",
+ error);
+ return (error);
+ }
+
+ /* Match against requested variable name */
+ if (keylen == namelen &&
+ strncmp(key, name, namelen) == 0)
+ {
+ return (bhnd_nvram_value_coerce(value, vlen,
+ BHND_NVRAM_TYPE_STRING, buf, len, type));
+ }
+
+ break;
+
+ default:
+ /* Skip unknown tags */
+ break;
+ }
+ }
+
+ /* Hit I/O error */
+ return (error);
+}
+
+static int
bhnd_nvram_tlv_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
bhnd_nvram_plist *options, void *outp, size_t *olen)
{
Index: sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
+++ sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
@@ -55,6 +55,11 @@
/** @see bhnd_nvram_data_probe() */
typedef int (bhnd_nvram_data_op_probe)(struct bhnd_nvram_io *io);
+/** @see bhnd_nvram_data_probe() */
+typedef int (bhnd_nvram_data_op_getvar_direct)(
+ struct bhnd_nvram_io *io, const char *name,
+ void *outp, size_t *olen, bhnd_nvram_type otype);
+
/** @see bhnd_nvram_data_serialize() */
typedef int (bhnd_nvram_data_op_serialize)(
bhnd_nvram_data_class *cls,
@@ -131,6 +136,7 @@
size_t size; /**< instance size */
bhnd_nvram_data_op_probe *op_probe;
+ bhnd_nvram_data_op_getvar_direct *op_getvar_direct;
bhnd_nvram_data_op_serialize *op_serialize;
bhnd_nvram_data_op_new *op_new;
bhnd_nvram_data_op_free *op_free;
@@ -184,6 +190,7 @@
*/
#define BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, _macro) \
_macro(_cname, probe) \
+ _macro(_cname, getvar_direct) \
_macro(_cname, serialize) \
_macro(_cname, new) \
_macro(_cname, free) \
Index: sys/dev/bhnd/nvram/bhnd_sprom.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_sprom.c
+++ sys/dev/bhnd/nvram/bhnd_sprom.c
@@ -120,9 +120,9 @@
sprom_size = r_size - offset;
- /* Allocate an I/O context for the SPROM parser. All SPROM reads
- * must be 16-bit aligned */
- io = bhnd_nvram_iores_new(r, offset, sprom_size, sizeof(uint16_t));
+ /* Allocate an I/O context for the SPROM parser. SPROM reads do not
+ * appear to require any specific alignment. */
+ io = bhnd_nvram_iores_new(r, offset, sprom_size, 1);
if (io == NULL) {
error = ENXIO;
goto failed;
Index: sys/mips/broadcom/bcm_machdep.h
===================================================================
--- sys/mips/broadcom/bcm_machdep.h
+++ sys/mips/broadcom/bcm_machdep.h
@@ -40,6 +40,8 @@
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
+#include "bcm_nvram_cfevar.h"
+
extern const struct bhnd_pmu_io bcm_pmu_soc_io;
struct bcm_platform {
@@ -65,6 +67,9 @@
bhnd_erom_t obj;
} erom;
+ struct bhnd_nvram_io *nvram_io; /**< NVRAM I/O context, or NULL if unavailable */
+ bhnd_nvram_data_class *nvram_cls; /**< NVRAM data class, or NULL if unavailable */
+
#ifdef CFE
int cfe_console; /**< Console handle, or -1 */
#endif
@@ -79,6 +84,10 @@
u_int bcm_get_uart_rclk(struct bcm_platform *bp);
+int bcm_get_nvram(struct bcm_platform *bp,
+ const char *name, void *outp, size_t *olen,
+ bhnd_nvram_type type);
+
#define BCM_ERR(fmt, ...) \
printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
Index: sys/mips/broadcom/bcm_machdep.c
===================================================================
--- sys/mips/broadcom/bcm_machdep.c
+++ sys/mips/broadcom/bcm_machdep.c
@@ -88,6 +88,7 @@
#ifdef CFE
#include <dev/cfe/cfe_api.h>
+#include <dev/cfe/cfe_error.h>
#endif
#if 0
@@ -112,6 +113,10 @@
static struct bcm_platform bcm_platform_data;
static bool bcm_platform_data_avail = false;
+#ifdef CFE
+static struct bcm_nvram_iocfe bcm_cfe_nvram;
+#endif
+
struct bcm_platform *
bcm_get_platform(void)
{
@@ -179,6 +184,40 @@
}
/**
+ * Read a variable directly from NVRAM, decoding as @p type.
+ *
+ * @param bp Platform state.
+ * @param name The raw name of the variable to be fetched,
+ * including any device path (/pci/1/1/varname) or
+ * alias prefix (0:varname).
+ * @param[out] buf On success, the requested value will be written
+ * to this buffer. This argment may be NULL if
+ * the value is not desired.
+ * @param[in,out] len The capacity of @p buf. On success, will be set
+ * to the actual size of the requested value.
+ * @param type The data type to be written to @p buf.
+ *
+ * @retval 0 success
+ * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
+ * small to hold the requested value.
+ * @retval ENOENT If @p name is not found.
+ * @retval EFTYPE If the variable data cannot be coerced to @p type.
+ * @retval ERANGE If value coercion would overflow @p type.
+ * @retval non-zero If parsing NVRAM otherwise fails, a regular unix error
+ * code will be returned.
+ */
+int
+bcm_get_nvram(struct bcm_platform *bp, const char *name, void *buf, size_t *len,
+ bhnd_nvram_type type)
+{
+ if (bp->nvram_io == NULL || bp->nvram_cls == NULL)
+ return (ENOENT);
+
+ return (bhnd_nvram_data_getvar_direct(bp->nvram_cls, bp->nvram_io, name,
+ buf, len, type));
+}
+
+/**
* Probe and attach a bhnd_erom parser instance for the bhnd bus.
*
* @param[out] erom_cls The probed EROM class.
@@ -269,12 +308,20 @@
bool aob, pmu;
int error;
+#ifdef CFE
/* Fetch CFE console handle (if any). Must be initialized before
* any calls to printf/early_putc. */
-#ifdef CFE
if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
bp->cfe_console = -1;
-#endif
+
+ /* Probe CFE NVRAM sources */
+ bp->nvram_io = &bcm_cfe_nvram.io;
+ error = bcm_nvram_find_cfedev(&bcm_cfe_nvram, &bp->nvram_cls);
+ if (error) {
+ bp->nvram_io = NULL;
+ bp->nvram_cls = NULL;
+ }
+#endif /* CFE */
/* Probe and attach device table provider, populating our
* chip identification */
Index: sys/mips/broadcom/bcm_nvram_cfe.c
===================================================================
--- sys/mips/broadcom/bcm_nvram_cfe.c
+++ sys/mips/broadcom/bcm_nvram_cfe.c
@@ -54,36 +54,18 @@
#include <dev/cfe/cfe_error.h>
#include <dev/cfe/cfe_ioctl.h>
-#include <dev/bhnd/nvram/bhnd_nvram_iovar.h>
-
#include "bhnd_nvram_if.h"
+#include "bcm_machdep.h"
#include "bcm_nvram_cfevar.h"
-/**
- * CFE-backed bhnd_nvram_io implementation.
- */
-struct bhnd_nvram_iocfe {
- struct bhnd_nvram_io io; /**< common I/O instance state */
-
- char *dname; /**< CFE device name (borrowed) */
- int fd; /**< CFE file descriptor */
- size_t offset; /**< base offset */
- size_t size; /**< device size */
- bool req_blk_erase; /**< flash blocks must be erased
- before writing */
-};
-
BHND_NVRAM_IOPS_DEFN(iocfe)
#define IOCFE_LOG(_io, _fmt, ...) \
printf("%s/%s: " _fmt, __FUNCTION__, (_io)->dname, ##__VA_ARGS__)
-static int bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io,
- char *dname);
-
-static struct bhnd_nvram_io *bhnd_nvram_find_cfedev(device_t dev,
- char **dname, bhnd_nvram_data_class **cls);
+static int bcm_nvram_iocfe_init(struct bcm_nvram_iocfe *iocfe,
+ char *dname);
/** Known CFE NVRAM device names, in probe order. */
static char *nvram_cfe_devs[] = {
@@ -99,31 +81,20 @@
&bhnd_nvram_tlv_class
};
-
static int
bhnd_nvram_cfe_probe(device_t dev)
{
- struct bhnd_nvram_io *io;
- bhnd_nvram_data_class *cls;
- const char *cls_desc;
- char *dname;
- char *desc;
-
- /* Locate a usable CFE device */
- io = bhnd_nvram_find_cfedev(dev, &dname, &cls);
- if (io == NULL)
+ struct bcm_platform *bp;
+
+ /* Fetch platform NVRAM I/O context */
+ bp = bcm_get_platform();
+ if (bp->nvram_io == NULL)
return (ENXIO);
- bhnd_nvram_io_free(io);
-
- /* Format the device description */
- cls_desc = bhnd_nvram_data_class_desc(cls);
- asprintf(&desc, M_DEVBUF, "%s CFE %s", cls_desc, dname);
- if (desc != NULL) {
- device_set_desc_copy(dev, desc);
- free(desc, M_DEVBUF);
- } else {
- device_set_desc(dev, cls_desc);
- }
+
+ KASSERT(bp->nvram_cls != NULL, ("missing NVRAM class"));
+
+ /* Set the device description */
+ device_set_desc(dev, bhnd_nvram_data_class_desc(bp->nvram_cls));
/* Refuse wildcard attachments */
return (BUS_PROBE_NOWILDCARD);
@@ -133,25 +104,19 @@
static int
bhnd_nvram_cfe_attach(device_t dev)
{
+ struct bcm_platform *bp;
struct bhnd_nvram_cfe_softc *sc;
- bhnd_nvram_data_class *cls;
- struct bhnd_nvram_io *io;
- char *dname;
int error;
+ bp = bcm_get_platform();
+ KASSERT(bp->nvram_io != NULL, ("missing NVRAM I/O context"));
+ KASSERT(bp->nvram_cls != NULL, ("missing NVRAM class"));
+
sc = device_get_softc(dev);
sc->dev = dev;
- /* Locate NVRAM device via CFE */
- io = bhnd_nvram_find_cfedev(dev, &dname, &cls);
- if (io == NULL) {
- device_printf(dev, "CFE NVRAM device not found\n");
- return (ENXIO);
- }
-
- /* Initialize NVRAM store and free the I/O context */
- error = bhnd_nvram_store_parse_new(&sc->store, io, cls);
- bhnd_nvram_io_free(io);
+ error = bhnd_nvram_store_parse_new(&sc->store, bp->nvram_io,
+ bp->nvram_cls);
if (error)
return (error);
@@ -201,79 +166,79 @@
}
/**
- * Find, open, identify, and return an I/O context mapping our
- * CFE NVRAM device.
+ * Find, open, identify, and initialize an I/O context mapping the CFE NVRAM
+ * device.
*
- * @param dev bhnd_nvram_cfe device.
- * @param[out] dname On success, the CFE device name.
+ * @param[out] iocfe On success, an I/O context mapping the CFE NVRAM
+ * device.
* @param[out] cls On success, the identified NVRAM data format
* class.
*
- * @retval non-NULL success. the caller inherits ownership of the returned
- * NVRAM I/O context.
- * @retval NULL if no usable CFE NVRAM device could be found.
+ * @retval 0 success. the caller inherits ownership of @p iocfe.
+ * @retval non-zero if no usable CFE NVRAM device can be found, a standard
+ * unix error will be returned.
*/
-static struct bhnd_nvram_io *
-bhnd_nvram_find_cfedev(device_t dev, char **dname, bhnd_nvram_data_class **cls)
+int
+bcm_nvram_find_cfedev(struct bcm_nvram_iocfe *iocfe,
+ bhnd_nvram_data_class **cls)
{
- struct bhnd_nvram_io *io;
- int devinfo;
- int error, result;
+ char *dname;
+ int devinfo;
+ int error, result;
for (u_int i = 0; i < nitems(nvram_cfe_fmts); i++) {
*cls = nvram_cfe_fmts[i];
for (u_int j = 0; j < nitems(nvram_cfe_devs); j++) {
- *dname = nvram_cfe_devs[j];
+ dname = nvram_cfe_devs[j];
/* Does the device exist? */
- if ((devinfo = cfe_getdevinfo(*dname)) < 0) {
+ if ((devinfo = cfe_getdevinfo(dname)) < 0) {
if (devinfo != CFE_ERR_DEVNOTFOUND) {
- device_printf(dev, "cfe_getdevinfo(%s) "
- "failed: %d\n", *dname, devinfo);
+ BCM_ERR("cfe_getdevinfo(%s) failed: "
+ "%d\n", dname, devinfo);
}
continue;
}
/* Open for reading */
- if ((error = bhnd_nvram_iocfe_new(&io, *dname)))
+ if ((error = bcm_nvram_iocfe_init(iocfe, dname)))
continue;
/* Probe */
- result = bhnd_nvram_data_probe(*cls, io);
+ result = bhnd_nvram_data_probe(*cls, &iocfe->io);
if (result <= 0) {
/* Found a supporting NVRAM data class */
- return (io);
+ return (0);
}
/* Keep searching */
- bhnd_nvram_io_free(io);
- io = NULL;
+ bhnd_nvram_io_free(&iocfe->io);
}
}
- return (NULL);
+ return (ENODEV);
}
/**
- * Allocate and return a new I/O context backed by a CFE device.
+ * Initialize a new CFE device-backed I/O context.
*
- * The caller is responsible for deallocating the returned I/O context via
- * bhnd_nvram_io_free().
+ * The caller is responsible for releasing all resources held by the returned
+ * I/O context via bhnd_nvram_io_free().
*
- * @param[out] io On success, a valid I/O context for @p dname.
- * @param dname The name of the CFE device to be opened for reading.
+ * @param[out] io On success, will be initialized as an I/O context for
+ * CFE device @p dname.
+ * @param dname The name of the CFE device to be opened for reading.
*
- * @retval 0 success.
- * @retval non-zero if opening @p dname otherwise fails, a standard unix error
- * will be returned.
+ * @retval 0 success.
+ * @retval non-zero if opening @p dname otherwise fails, a standard unix
+ * error will be returned.
*/
static int
-bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname)
+bcm_nvram_iocfe_init(struct bcm_nvram_iocfe *iocfe, char *dname)
{
- struct bhnd_nvram_iocfe *iocfe;
nvram_info_t nvram_info;
int cerr, devinfo, dtype, rlen;
int64_t nv_offset;
@@ -281,7 +246,6 @@
bool req_blk_erase;
int error;
- iocfe = malloc(sizeof(*iocfe), M_DEVBUF, M_WAITOK);
iocfe->io.iops = &bhnd_nvram_iocfe_ops;
iocfe->dname = dname;
@@ -290,8 +254,7 @@
if (iocfe->fd <= 0) {
IOCFE_LOG(iocfe, "cfe_open() failed: %d\n", iocfe->fd);
- error = ENXIO;
- goto failed;
+ return (ENXIO);
}
/* Try to fetch device info */
@@ -374,32 +337,29 @@
iocfe->size = nv_size;
iocfe->req_blk_erase = req_blk_erase;
- *io = &iocfe->io;
return (CFE_OK);
failed:
if (iocfe->fd >= 0)
cfe_close(iocfe->fd);
- free(iocfe, M_DEVBUF);
-
- *io = NULL;
return (error);
}
static void
bhnd_nvram_iocfe_free(struct bhnd_nvram_io *io)
{
- struct bhnd_nvram_iocfe *iocfe = (struct bhnd_nvram_iocfe *)io;
+ struct bcm_nvram_iocfe *iocfe = (struct bcm_nvram_iocfe *)io;
+ /* CFE I/O instances are statically allocated; we do not need to free
+ * the instance itself */
cfe_close(iocfe->fd);
- free(io, M_DEVBUF);
}
static size_t
bhnd_nvram_iocfe_getsize(struct bhnd_nvram_io *io)
{
- struct bhnd_nvram_iocfe *iocfe = (struct bhnd_nvram_iocfe *)io;
+ struct bcm_nvram_iocfe *iocfe = (struct bcm_nvram_iocfe *)io;
return (iocfe->size);
}
@@ -438,12 +398,12 @@
bhnd_nvram_iocfe_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
size_t nbytes)
{
- struct bhnd_nvram_iocfe *iocfe;
+ struct bcm_nvram_iocfe *iocfe;
size_t remain;
int64_t cfe_offset;
int nr, nreq;
- iocfe = (struct bhnd_nvram_iocfe *)io;
+ iocfe = (struct bcm_nvram_iocfe *)io;
/* Determine (and validate) the base CFE offset */
#if (SIZE_MAX > INT64_MAX)
Index: sys/mips/broadcom/bcm_nvram_cfevar.h
===================================================================
--- sys/mips/broadcom/bcm_nvram_cfevar.h
+++ sys/mips/broadcom/bcm_nvram_cfevar.h
@@ -36,8 +36,28 @@
#include <sys/bus.h>
#include <dev/bhnd/nvram/bhnd_nvram.h>
+#include <dev/bhnd/nvram/bhnd_nvram_iovar.h>
#include <dev/bhnd/nvram/bhnd_nvram_store.h>
+struct bcm_nvram_iocfe;
+
+int bcm_nvram_find_cfedev(struct bcm_nvram_iocfe *iocfe,
+ bhnd_nvram_data_class **cls);
+
+/**
+ * CFE-backed bhnd_nvram_io implementation.
+ */
+struct bcm_nvram_iocfe {
+ struct bhnd_nvram_io io; /**< common I/O instance state */
+
+ char *dname; /**< CFE device name (borrowed) */
+ int fd; /**< CFE file descriptor */
+ size_t offset; /**< base offset */
+ size_t size; /**< device size */
+ bool req_blk_erase; /**< flash blocks must be erased
+ before writing */
+};
+
/** bhnd_nvram_cfe driver instance state. */
struct bhnd_nvram_cfe_softc {
device_t dev;

File Metadata

Mime Type
text/plain
Expires
Sun, Jan 25, 2:44 PM (14 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27946707
Default Alt Text
D9913.id26043.diff (49 KB)

Event Timeline