Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142937433
D9913.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
50 KB
Referenced Files
None
Subscribers
None
D9913.diff
View Options
Index: head/sys/dev/bhnd/nvram/bhnd_nvram_data.h
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data.h
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data.c
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmvar.h
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmvar.h
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
+++ head/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);
+
+ crc = bhnd_nvram_crc8(buf, nr, crc);
+ crc_valid = (crc == BHND_NVRAM_CRC8_VALID);
+ if (!crc_valid)
+ crc_errors++;
- /* 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(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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
+++ head/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: head/sys/dev/bhnd/nvram/bhnd_sprom.c
===================================================================
--- head/sys/dev/bhnd/nvram/bhnd_sprom.c
+++ head/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: head/sys/mips/broadcom/bcm_machdep.h
===================================================================
--- head/sys/mips/broadcom/bcm_machdep.h
+++ head/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: head/sys/mips/broadcom/bcm_machdep.c
===================================================================
--- head/sys/mips/broadcom/bcm_machdep.c
+++ head/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
+
static const struct bhnd_core_match bcm_chipc_cores[] = {
{ BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_CC) },
{ BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_4706_CC) },
@@ -190,6 +195,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.
@@ -280,12 +319,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: head/sys/mips/broadcom/bcm_nvram_cfe.c
===================================================================
--- head/sys/mips/broadcom/bcm_nvram_cfe.c
+++ head/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)
-{
- struct bhnd_nvram_io *io;
- int devinfo;
- int error, result;
+int
+bcm_nvram_find_cfedev(struct bcm_nvram_iocfe *iocfe,
+ bhnd_nvram_data_class **cls)
+{
+ 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: head/sys/mips/broadcom/bcm_nvram_cfevar.h
===================================================================
--- head/sys/mips/broadcom/bcm_nvram_cfevar.h
+++ head/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
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 25, 8:02 PM (20 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27965051
Default Alt Text
D9913.diff (50 KB)
Attached To
Mode
D9913: mips/broadcom: Early boot NVRAM support
Attached
Detach File
Event Timeline
Log In to Comment