[mips/broadcom]: Early boot NVRAM support
Add support for early boot access to NVRAM variables, using a new bhnd_nvram_data_getvar_direct() API to support zero-allocation direct reading of NVRAM variables from a bhnd_nvram_io instance backed by the CFE NVRAM device. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D9913
This commit is contained in:
parent
8f7eee5a63
commit
591e79bc76
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=315866
@ -227,6 +227,41 @@ bhnd_nvram_data_probe_classes(struct bhnd_nvram_data **data,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Allocate and initialize a new instance of data class @p cls, copying and
|
||||||
* parsing NVRAM data from @p io.
|
* parsing NVRAM data from @p io.
|
||||||
|
@ -105,6 +105,11 @@ int bhnd_nvram_data_probe_classes(
|
|||||||
bhnd_nvram_data_class *classes[],
|
bhnd_nvram_data_class *classes[],
|
||||||
size_t num_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,
|
int bhnd_nvram_data_new(bhnd_nvram_data_class *cls,
|
||||||
struct bhnd_nvram_data **nv,
|
struct bhnd_nvram_data **nv,
|
||||||
struct bhnd_nvram_io *io);
|
struct bhnd_nvram_io *io);
|
||||||
|
@ -144,9 +144,229 @@ bhnd_nvram_bcm_probe(struct bhnd_nvram_io *io)
|
|||||||
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
|
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
|
if (le32toh(hdr.size) > bhnd_nvram_io_getsize(io))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
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
|
static int
|
||||||
bhnd_nvram_bcm_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
bhnd_nvram_bcm_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
||||||
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
||||||
|
@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include "bhnd_nvram_private.h"
|
#include "bhnd_nvram_private.h"
|
||||||
|
|
||||||
#include "bhnd_nvram_datavar.h"
|
#include "bhnd_nvram_datavar.h"
|
||||||
|
#include "bhnd_nvram_data_bcmvar.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Broadcom-RAW NVRAM data class.
|
* Broadcom-RAW NVRAM data class.
|
||||||
@ -132,6 +133,14 @@ bhnd_nvram_bcmraw_probe(struct bhnd_nvram_io *io)
|
|||||||
return (BHND_NVRAM_DATA_PROBE_MAYBE + 1);
|
return (BHND_NVRAM_DATA_PROBE_MAYBE + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static int
|
||||||
bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
||||||
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
||||||
|
@ -69,4 +69,8 @@ struct bhnd_nvram_bcmhdr {
|
|||||||
uint32_t sdram_ncdl; /**< sdram_ncdl */
|
uint32_t sdram_ncdl; /**< sdram_ncdl */
|
||||||
} __packed;
|
} __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_ */
|
#endif /* _BHND_NVRAM_BHND_NVRAM_BCMVAR_H_ */
|
||||||
|
@ -124,6 +124,226 @@ bhnd_nvram_btxt_probe(struct bhnd_nvram_io *io)
|
|||||||
return (BHND_NVRAM_DATA_PROBE_MAYBE);
|
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
|
static int
|
||||||
bhnd_nvram_btxt_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
bhnd_nvram_btxt_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
||||||
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
||||||
|
@ -68,8 +68,7 @@ static const bhnd_sprom_layout *bhnd_nvram_sprom_get_layout(uint8_t sromrev);
|
|||||||
|
|
||||||
static int bhnd_nvram_sprom_ident(
|
static int bhnd_nvram_sprom_ident(
|
||||||
struct bhnd_nvram_io *io,
|
struct bhnd_nvram_io *io,
|
||||||
const bhnd_sprom_layout **ident,
|
const bhnd_sprom_layout **ident);
|
||||||
struct bhnd_nvram_io **shadow);
|
|
||||||
|
|
||||||
static int bhnd_nvram_sprom_write_var(
|
static int bhnd_nvram_sprom_write_var(
|
||||||
bhnd_sprom_opcode_state *state,
|
bhnd_sprom_opcode_state *state,
|
||||||
@ -77,6 +76,13 @@ static int bhnd_nvram_sprom_write_var(
|
|||||||
bhnd_nvram_val *value,
|
bhnd_nvram_val *value,
|
||||||
struct bhnd_nvram_io *io);
|
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(
|
static int bhnd_nvram_sprom_write_offset(
|
||||||
const struct bhnd_nvram_vardefn *var,
|
const struct bhnd_nvram_vardefn *var,
|
||||||
struct bhnd_nvram_io *data,
|
struct bhnd_nvram_io *data,
|
||||||
@ -153,10 +159,6 @@ bhnd_nvram_sprom_check_magic(struct bhnd_nvram_io *io,
|
|||||||
*
|
*
|
||||||
* @param io An I/O context mapping the SPROM data to be identified.
|
* @param io An I/O context mapping the SPROM data to be identified.
|
||||||
* @param[out] ident On success, the identified SPROM layout.
|
* @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 0 success
|
||||||
* @retval non-zero If identifying @p io otherwise fails, a regular unix
|
* @retval non-zero If identifying @p io otherwise fails, a regular unix
|
||||||
@ -164,77 +166,69 @@ bhnd_nvram_sprom_check_magic(struct bhnd_nvram_io *io,
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io,
|
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;
|
||||||
uint8_t crc;
|
size_t crc_errors;
|
||||||
size_t crc_errors;
|
size_t nbytes;
|
||||||
size_t sprom_sz_max;
|
int error;
|
||||||
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 = BHND_NVRAM_CRC8_INITIAL;
|
||||||
crc_errors = 0;
|
crc_errors = 0;
|
||||||
|
nbytes = 0;
|
||||||
|
|
||||||
/* We iterate the SPROM layouts smallest to largest, allowing us to
|
/* We iterate the SPROM layouts smallest to largest, allowing us to
|
||||||
* perform incremental checksum calculation */
|
* perform incremental checksum calculation */
|
||||||
for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) {
|
for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) {
|
||||||
const bhnd_sprom_layout *layout;
|
const bhnd_sprom_layout *layout;
|
||||||
void *ptr;
|
u_char buf[512];
|
||||||
size_t nbytes, nr;
|
size_t nread;
|
||||||
uint16_t magic;
|
uint16_t magic;
|
||||||
uint8_t srev;
|
uint8_t srev;
|
||||||
bool crc_valid;
|
bool crc_valid;
|
||||||
bool have_magic;
|
bool have_magic;
|
||||||
|
|
||||||
layout = &bhnd_sprom_layouts[i];
|
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;
|
have_magic = false;
|
||||||
} else {
|
|
||||||
have_magic = true;
|
/*
|
||||||
|
* 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 defined out-of-order");
|
||||||
|
|
||||||
|
nread = layout->size - nbytes;
|
||||||
|
|
||||||
|
while (nread > 0) {
|
||||||
|
size_t nr;
|
||||||
|
|
||||||
|
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++;
|
||||||
|
|
||||||
|
nread -= nr;
|
||||||
|
nbytes += nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Layout instances must be ordered from smallest to largest by
|
/* Read SPROM revision */
|
||||||
* the nvram_map compiler */
|
error = bhnd_nvram_io_read(io, layout->srev_offset, &srev,
|
||||||
if (nbytes > layout->size)
|
|
||||||
BHND_NV_PANIC("SPROM layout is defined out-of-order");
|
|
||||||
|
|
||||||
/* Calculate number of additional bytes to be read */
|
|
||||||
nr = layout->size - nbytes;
|
|
||||||
|
|
||||||
/* Adjust the buffer size and fetch a write pointer */
|
|
||||||
if ((error = bhnd_nvram_io_setsize(buf, layout->size)))
|
|
||||||
goto failed;
|
|
||||||
|
|
||||||
error = bhnd_nvram_io_write_ptr(buf, nbytes, &ptr, nr, NULL);
|
|
||||||
if (error)
|
|
||||||
goto failed;
|
|
||||||
|
|
||||||
/* 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++;
|
|
||||||
|
|
||||||
/* Fetch SPROM revision */
|
|
||||||
error = bhnd_nvram_io_read(buf, layout->srev_offset, &srev,
|
|
||||||
sizeof(srev));
|
sizeof(srev));
|
||||||
if (error)
|
if (error)
|
||||||
goto failed;
|
return (error);
|
||||||
|
|
||||||
/* Early sromrev 1 devices (specifically some BCM440x enet
|
/* Early sromrev 1 devices (specifically some BCM440x enet
|
||||||
* cards) are reported to have been incorrectly programmed
|
* cards) are reported to have been incorrectly programmed
|
||||||
@ -248,7 +242,7 @@ bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io,
|
|||||||
|
|
||||||
/* Check the magic value, skipping to the next layout on
|
/* Check the magic value, skipping to the next layout on
|
||||||
* failure. */
|
* failure. */
|
||||||
error = bhnd_nvram_sprom_check_magic(buf, layout, &magic);
|
error = bhnd_nvram_sprom_check_magic(io, layout, &magic);
|
||||||
if (error) {
|
if (error) {
|
||||||
/* If the CRC is was valid, log the mismatch */
|
/* If the CRC is was valid, log the mismatch */
|
||||||
if (crc_valid || BHND_NV_VERBOSE) {
|
if (crc_valid || BHND_NV_VERBOSE) {
|
||||||
@ -256,8 +250,7 @@ bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io,
|
|||||||
"0x%hx (expected 0x%hx)\n", srev,
|
"0x%hx (expected 0x%hx)\n", srev,
|
||||||
magic, layout->magic_value);
|
magic, layout->magic_value);
|
||||||
|
|
||||||
error = ENXIO;
|
return (ENXIO);
|
||||||
goto failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -277,40 +270,93 @@ bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Identified */
|
/* Identified */
|
||||||
*shadow = buf;
|
|
||||||
*ident = layout;
|
*ident = layout;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No match -- set error and fallthrough */
|
/* No match */
|
||||||
error = ENXIO;
|
|
||||||
if (crc_errors > 0 && BHND_NV_VERBOSE) {
|
if (crc_errors > 0 && BHND_NV_VERBOSE) {
|
||||||
BHND_NV_LOG("sprom parsing failed with %zu CRC errors\n",
|
BHND_NV_LOG("sprom parsing failed with %zu CRC errors\n",
|
||||||
crc_errors);
|
crc_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
failed:
|
return (ENXIO);
|
||||||
bhnd_nvram_io_free(buf);
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bhnd_nvram_sprom_probe(struct bhnd_nvram_io *io)
|
bhnd_nvram_sprom_probe(struct bhnd_nvram_io *io)
|
||||||
{
|
{
|
||||||
const bhnd_sprom_layout *layout;
|
const bhnd_sprom_layout *layout;
|
||||||
struct bhnd_nvram_io *shadow;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Try to parse the input */
|
/* Try to parse the input */
|
||||||
if ((error = bhnd_nvram_sprom_ident(io, &layout, &shadow)))
|
if ((error = bhnd_nvram_sprom_ident(io, &layout)))
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
/* Clean up the shadow iobuf */
|
|
||||||
bhnd_nvram_io_free(shadow);
|
|
||||||
|
|
||||||
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
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
|
* Return the SPROM layout definition for the given @p sromrev, or NULL if
|
||||||
@ -365,7 +411,7 @@ bhnd_nvram_sprom_write_var(bhnd_sprom_opcode_state *state,
|
|||||||
var_base_type = bhnd_nvram_base_type(var->type);
|
var_base_type = bhnd_nvram_base_type(var->type);
|
||||||
|
|
||||||
/* Fetch the element count from the SPROM variable layout definition */
|
/* 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);
|
return (error);
|
||||||
|
|
||||||
nelem = state->var.nelem;
|
nelem = state->var.nelem;
|
||||||
@ -717,7 +763,12 @@ bhnd_nvram_sprom_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
|
|||||||
sp = (struct bhnd_nvram_sprom *)nv;
|
sp = (struct bhnd_nvram_sprom *)nv;
|
||||||
|
|
||||||
/* Identify the SPROM input data */
|
/* 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;
|
goto failed;
|
||||||
|
|
||||||
/* Initialize SPROM binding eval state */
|
/* Initialize SPROM binding eval state */
|
||||||
@ -989,9 +1040,15 @@ bhnd_nvram_sprom_read_offset(const struct bhnd_nvram_vardefn *var,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common variable decoding; fetches and decodes variable to @p val,
|
* Read a SPROM variable value from @p io.
|
||||||
* using @p storage for actual data storage.
|
|
||||||
*
|
*
|
||||||
|
* @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,
|
* 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
|
* and must be copied via bhnd_nvram_val_copy() if it will be referenced beyond
|
||||||
* the lifetime of @p storage.
|
* the lifetime of @p storage.
|
||||||
@ -1000,13 +1057,12 @@ bhnd_nvram_sprom_read_offset(const struct bhnd_nvram_vardefn *var,
|
|||||||
* via bhnd_nvram_val_release().
|
* via bhnd_nvram_val_release().
|
||||||
*/
|
*/
|
||||||
static int
|
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)
|
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;
|
union bhnd_nvram_sprom_storage *inp;
|
||||||
|
const struct bhnd_nvram_vardefn *var;
|
||||||
bhnd_nvram_type var_btype;
|
bhnd_nvram_type var_btype;
|
||||||
uint32_t intv;
|
uint32_t intv;
|
||||||
size_t ilen, ipos, iwidth;
|
size_t ilen, ipos, iwidth;
|
||||||
@ -1014,14 +1070,9 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
bool all_bits_set;
|
bool all_bits_set;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
sp = (struct bhnd_nvram_sprom *)nv;
|
|
||||||
entry = cookiep;
|
|
||||||
|
|
||||||
BHND_NV_ASSERT(cookiep != NULL, ("NULL variable cookiep"));
|
|
||||||
|
|
||||||
/* Fetch canonical variable definition */
|
/* Fetch canonical variable definition */
|
||||||
var = SPROM_COOKIE_TO_NVRAM_VAR(cookiep);
|
var = bhnd_nvram_get_vardefn(entry->vid);
|
||||||
BHND_NV_ASSERT(var != NULL, ("invalid cookiep %p", cookiep));
|
BHND_NV_ASSERT(var != NULL, ("invalid entry"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the array length from the SPROM variable definition.
|
* Fetch the array length from the SPROM variable definition.
|
||||||
@ -1030,12 +1081,12 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
* canonical NVRAM variable definition, but some SPROM layouts may
|
* canonical NVRAM variable definition, but some SPROM layouts may
|
||||||
* define a smaller element count.
|
* 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);
|
BHND_NV_LOG("variable evaluation failed: %d\n", error);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
nelem = sp->state.var.nelem;
|
nelem = state->var.nelem;
|
||||||
if (nelem > var->nelem) {
|
if (nelem > var->nelem) {
|
||||||
BHND_NV_LOG("SPROM array element count %zu cannot be "
|
BHND_NV_LOG("SPROM array element count %zu cannot be "
|
||||||
"represented by '%s' element count of %hhu\n", nelem,
|
"represented by '%s' element count of %hhu\n", nelem,
|
||||||
@ -1070,7 +1121,7 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
/*
|
/*
|
||||||
* Decode the SPROM data, iteratively decoding up to nelem values.
|
* 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);
|
BHND_NV_LOG("variable seek failed: %d\n", error);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -1081,7 +1132,7 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
all_bits_set = true;
|
all_bits_set = true;
|
||||||
else
|
else
|
||||||
all_bits_set = false;
|
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_bind *binding;
|
||||||
bhnd_sprom_opcode_var *binding_var;
|
bhnd_sprom_opcode_var *binding_var;
|
||||||
bhnd_nvram_type intv_type;
|
bhnd_nvram_type intv_type;
|
||||||
@ -1091,12 +1142,12 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
void *ptr;
|
void *ptr;
|
||||||
|
|
||||||
BHND_NV_ASSERT(
|
BHND_NV_ASSERT(
|
||||||
sp->state.var_state >= SPROM_OPCODE_VAR_STATE_OPEN,
|
state->var_state >= SPROM_OPCODE_VAR_STATE_OPEN,
|
||||||
("invalid var state"));
|
("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_var = &state->var;
|
||||||
binding = &sp->state.var.bind;
|
binding = &state->var.bind;
|
||||||
|
|
||||||
if (ipos >= nelem) {
|
if (ipos >= nelem) {
|
||||||
BHND_NV_LOG("output skip %u positioned "
|
BHND_NV_LOG("output skip %u positioned "
|
||||||
@ -1107,17 +1158,16 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
|
|
||||||
/* Calculate input skip bytes for this binding */
|
/* Calculate input skip bytes for this binding */
|
||||||
skip_in_bytes = binding->skip_in;
|
skip_in_bytes = binding->skip_in;
|
||||||
error = bhnd_sprom_opcode_apply_scale(&sp->state,
|
error = bhnd_sprom_opcode_apply_scale(state, &skip_in_bytes);
|
||||||
&skip_in_bytes);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
/* Bind */
|
/* Bind */
|
||||||
offset = sp->state.offset;
|
offset = state->offset;
|
||||||
for (size_t i = 0; i < binding->count; i++) {
|
for (size_t i = 0; i < binding->count; i++) {
|
||||||
/* Read the offset value, OR'ing with the current
|
/* Read the offset value, OR'ing with the current
|
||||||
* value of intv */
|
* value of intv */
|
||||||
error = bhnd_nvram_sprom_read_offset(var, sp->data,
|
error = bhnd_nvram_sprom_read_offset(var, io,
|
||||||
binding_var->base_type,
|
binding_var->base_type,
|
||||||
offset,
|
offset,
|
||||||
binding_var->mask,
|
binding_var->mask,
|
||||||
@ -1209,6 +1259,39 @@ bhnd_nvram_sprom_getvar_common(struct bhnd_nvram_data *nv, void *cookiep,
|
|||||||
return (error);
|
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
|
static int
|
||||||
bhnd_nvram_sprom_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
|
bhnd_nvram_sprom_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
|
||||||
void *cookiep2)
|
void *cookiep2)
|
||||||
|
@ -51,7 +51,6 @@ static int bhnd_nvram_opcode_idx_vid_compare(const void *key,
|
|||||||
const void *rhs);
|
const void *rhs);
|
||||||
|
|
||||||
static int bhnd_sprom_opcode_reset(bhnd_sprom_opcode_state *state);
|
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,
|
static int bhnd_sprom_opcode_set_type(bhnd_sprom_opcode_state *state,
|
||||||
bhnd_nvram_type type);
|
bhnd_nvram_type type);
|
||||||
@ -108,8 +107,6 @@ bhnd_sprom_opcode_init(bhnd_sprom_opcode_state *state,
|
|||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
|
|
||||||
for (num_vars = 0; num_vars < num_idx; num_vars++) {
|
for (num_vars = 0; num_vars < num_idx; num_vars++) {
|
||||||
size_t opcodes;
|
|
||||||
|
|
||||||
/* Seek to next entry */
|
/* Seek to next entry */
|
||||||
if ((error = bhnd_sprom_opcode_next_var(state))) {
|
if ((error = bhnd_sprom_opcode_next_var(state))) {
|
||||||
SPROM_OP_BAD(state, "error reading expected variable "
|
SPROM_OP_BAD(state, "error reading expected variable "
|
||||||
@ -118,36 +115,14 @@ bhnd_sprom_opcode_init(bhnd_sprom_opcode_state *state,
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We limit the SPROM index representations to the minimal
|
/* Record entry state in our index */
|
||||||
* type widths capable of covering all known layouts */
|
error = bhnd_sprom_opcode_init_entry(state, &idx[num_vars]);
|
||||||
|
if (error) {
|
||||||
/* Save SPROM image offset */
|
SPROM_OP_BAD(state, "error initializing index for "
|
||||||
if (state->offset > UINT16_MAX) {
|
"entry: %d\n", error);
|
||||||
SPROM_OP_BAD(state, "cannot index large offset %u\n",
|
|
||||||
state->offset);
|
|
||||||
bhnd_nv_free(idx);
|
bhnd_nv_free(idx);
|
||||||
return (ENXIO);
|
return (error);
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
bhnd_nv_free(idx);
|
|
||||||
return (ENXIO);
|
|
||||||
}
|
|
||||||
idx[num_vars].opcodes = opcodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should have reached end of binding table; next read must return
|
/* Should have reached end of binding table; next read must return
|
||||||
@ -314,6 +289,54 @@ bhnd_sprom_opcode_index_next(bhnd_sprom_opcode_state *state,
|
|||||||
return (&state->idx[idxpos]);
|
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.
|
* Reset SPROM opcode evaluation state and seek to the @p entry's position.
|
||||||
*
|
*
|
||||||
@ -1255,7 +1278,7 @@ bhnd_sprom_opcode_step(bhnd_sprom_opcode_state *state, uint8_t *opcode)
|
|||||||
* returned.
|
* returned.
|
||||||
*/
|
*/
|
||||||
int
|
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)
|
bhnd_sprom_opcode_idx_entry *entry)
|
||||||
{
|
{
|
||||||
uint8_t opcode;
|
uint8_t opcode;
|
||||||
@ -1291,7 +1314,7 @@ bhnd_sprom_opcode_parse_var(bhnd_sprom_opcode_state *state,
|
|||||||
* @retval non-zero if evaluation otherwise fails, a regular unix error
|
* @retval non-zero if evaluation otherwise fails, a regular unix error
|
||||||
* code will be returned.
|
* code will be returned.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
bhnd_sprom_opcode_next_var(bhnd_sprom_opcode_state *state)
|
bhnd_sprom_opcode_next_var(bhnd_sprom_opcode_state *state)
|
||||||
{
|
{
|
||||||
uint8_t opcode;
|
uint8_t opcode;
|
||||||
|
@ -64,13 +64,19 @@ bhnd_sprom_opcode_idx_entry *bhnd_sprom_opcode_index_next(
|
|||||||
bhnd_sprom_opcode_state *state,
|
bhnd_sprom_opcode_state *state,
|
||||||
bhnd_sprom_opcode_idx_entry *prev);
|
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_state *state,
|
||||||
bhnd_sprom_opcode_idx_entry *entry);
|
bhnd_sprom_opcode_idx_entry *entry);
|
||||||
|
|
||||||
int bhnd_sprom_opcode_seek(
|
int bhnd_sprom_opcode_seek(
|
||||||
bhnd_sprom_opcode_state *state,
|
bhnd_sprom_opcode_state *state,
|
||||||
bhnd_sprom_opcode_idx_entry *entry);
|
bhnd_sprom_opcode_idx_entry *entry);
|
||||||
|
int bhnd_sprom_opcode_next_var(
|
||||||
|
bhnd_sprom_opcode_state *state);
|
||||||
int bhnd_sprom_opcode_next_binding(
|
int bhnd_sprom_opcode_next_binding(
|
||||||
bhnd_sprom_opcode_state *state);
|
bhnd_sprom_opcode_state *state);
|
||||||
int bhnd_sprom_opcode_apply_scale(
|
int bhnd_sprom_opcode_apply_scale(
|
||||||
|
@ -164,6 +164,78 @@ bhnd_nvram_tlv_probe(struct bhnd_nvram_io *io)
|
|||||||
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static int
|
||||||
bhnd_nvram_tlv_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
bhnd_nvram_tlv_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
|
||||||
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
bhnd_nvram_plist *options, void *outp, size_t *olen)
|
||||||
|
@ -55,6 +55,11 @@ int bhnd_nvram_data_generic_rp_copy_val(
|
|||||||
/** @see bhnd_nvram_data_probe() */
|
/** @see bhnd_nvram_data_probe() */
|
||||||
typedef int (bhnd_nvram_data_op_probe)(struct bhnd_nvram_io *io);
|
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() */
|
/** @see bhnd_nvram_data_serialize() */
|
||||||
typedef int (bhnd_nvram_data_op_serialize)(
|
typedef int (bhnd_nvram_data_op_serialize)(
|
||||||
bhnd_nvram_data_class *cls,
|
bhnd_nvram_data_class *cls,
|
||||||
@ -131,6 +136,7 @@ struct bhnd_nvram_data_class {
|
|||||||
size_t size; /**< instance size */
|
size_t size; /**< instance size */
|
||||||
|
|
||||||
bhnd_nvram_data_op_probe *op_probe;
|
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_serialize *op_serialize;
|
||||||
bhnd_nvram_data_op_new *op_new;
|
bhnd_nvram_data_op_new *op_new;
|
||||||
bhnd_nvram_data_op_free *op_free;
|
bhnd_nvram_data_op_free *op_free;
|
||||||
@ -184,6 +190,7 @@ struct bhnd_nvram_data {
|
|||||||
*/
|
*/
|
||||||
#define BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, _macro) \
|
#define BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, _macro) \
|
||||||
_macro(_cname, probe) \
|
_macro(_cname, probe) \
|
||||||
|
_macro(_cname, getvar_direct) \
|
||||||
_macro(_cname, serialize) \
|
_macro(_cname, serialize) \
|
||||||
_macro(_cname, new) \
|
_macro(_cname, new) \
|
||||||
_macro(_cname, free) \
|
_macro(_cname, free) \
|
||||||
|
@ -120,9 +120,9 @@ bhnd_sprom_attach(device_t dev, bus_size_t offset)
|
|||||||
|
|
||||||
sprom_size = r_size - offset;
|
sprom_size = r_size - offset;
|
||||||
|
|
||||||
/* Allocate an I/O context for the SPROM parser. All SPROM reads
|
/* Allocate an I/O context for the SPROM parser. SPROM reads do not
|
||||||
* must be 16-bit aligned */
|
* appear to require any specific alignment. */
|
||||||
io = bhnd_nvram_iores_new(r, offset, sprom_size, sizeof(uint16_t));
|
io = bhnd_nvram_iores_new(r, offset, sprom_size, 1);
|
||||||
if (io == NULL) {
|
if (io == NULL) {
|
||||||
error = ENXIO;
|
error = ENXIO;
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -88,6 +88,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#ifdef CFE
|
#ifdef CFE
|
||||||
#include <dev/cfe/cfe_api.h>
|
#include <dev/cfe/cfe_api.h>
|
||||||
|
#include <dev/cfe/cfe_error.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -112,6 +113,10 @@ extern int *end;
|
|||||||
static struct bcm_platform bcm_platform_data;
|
static struct bcm_platform bcm_platform_data;
|
||||||
static bool bcm_platform_data_avail = false;
|
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[] = {
|
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_CC) },
|
||||||
{ BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_4706_CC) },
|
{ BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_4706_CC) },
|
||||||
@ -189,6 +194,40 @@ bcm_find_core(struct bcm_platform *bp, const struct bhnd_core_match *descs,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Probe and attach a bhnd_erom parser instance for the bhnd bus.
|
||||||
*
|
*
|
||||||
@ -280,12 +319,20 @@ bcm_init_platform_data(struct bcm_platform *bp)
|
|||||||
bool aob, pmu;
|
bool aob, pmu;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
#ifdef CFE
|
||||||
/* Fetch CFE console handle (if any). Must be initialized before
|
/* Fetch CFE console handle (if any). Must be initialized before
|
||||||
* any calls to printf/early_putc. */
|
* any calls to printf/early_putc. */
|
||||||
#ifdef CFE
|
|
||||||
if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
|
if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
|
||||||
bp->cfe_console = -1;
|
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
|
/* Probe and attach device table provider, populating our
|
||||||
* chip identification */
|
* chip identification */
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
|
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
|
||||||
|
|
||||||
|
#include "bcm_nvram_cfevar.h"
|
||||||
|
|
||||||
extern const struct bhnd_pmu_io bcm_pmu_soc_io;
|
extern const struct bhnd_pmu_io bcm_pmu_soc_io;
|
||||||
|
|
||||||
struct bcm_platform {
|
struct bcm_platform {
|
||||||
@ -65,6 +67,9 @@ struct bcm_platform {
|
|||||||
bhnd_erom_t obj;
|
bhnd_erom_t obj;
|
||||||
} erom;
|
} 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
|
#ifdef CFE
|
||||||
int cfe_console; /**< Console handle, or -1 */
|
int cfe_console; /**< Console handle, or -1 */
|
||||||
#endif
|
#endif
|
||||||
@ -79,6 +84,10 @@ uint64_t bcm_get_ilpfreq(struct bcm_platform *bp);
|
|||||||
|
|
||||||
u_int bcm_get_uart_rclk(struct bcm_platform *bp);
|
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, ...) \
|
#define BCM_ERR(fmt, ...) \
|
||||||
printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
|
printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
@ -54,36 +54,18 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <dev/cfe/cfe_error.h>
|
#include <dev/cfe/cfe_error.h>
|
||||||
#include <dev/cfe/cfe_ioctl.h>
|
#include <dev/cfe/cfe_ioctl.h>
|
||||||
|
|
||||||
#include <dev/bhnd/nvram/bhnd_nvram_iovar.h>
|
|
||||||
|
|
||||||
#include "bhnd_nvram_if.h"
|
#include "bhnd_nvram_if.h"
|
||||||
|
|
||||||
|
#include "bcm_machdep.h"
|
||||||
#include "bcm_nvram_cfevar.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)
|
BHND_NVRAM_IOPS_DEFN(iocfe)
|
||||||
|
|
||||||
#define IOCFE_LOG(_io, _fmt, ...) \
|
#define IOCFE_LOG(_io, _fmt, ...) \
|
||||||
printf("%s/%s: " _fmt, __FUNCTION__, (_io)->dname, ##__VA_ARGS__)
|
printf("%s/%s: " _fmt, __FUNCTION__, (_io)->dname, ##__VA_ARGS__)
|
||||||
|
|
||||||
static int bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io,
|
static int bcm_nvram_iocfe_init(struct bcm_nvram_iocfe *iocfe,
|
||||||
char *dname);
|
char *dname);
|
||||||
|
|
||||||
static struct bhnd_nvram_io *bhnd_nvram_find_cfedev(device_t dev,
|
|
||||||
char **dname, bhnd_nvram_data_class **cls);
|
|
||||||
|
|
||||||
/** Known CFE NVRAM device names, in probe order. */
|
/** Known CFE NVRAM device names, in probe order. */
|
||||||
static char *nvram_cfe_devs[] = {
|
static char *nvram_cfe_devs[] = {
|
||||||
@ -99,31 +81,20 @@ static bhnd_nvram_data_class * const nvram_cfe_fmts[] = {
|
|||||||
&bhnd_nvram_tlv_class
|
&bhnd_nvram_tlv_class
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bhnd_nvram_cfe_probe(device_t dev)
|
bhnd_nvram_cfe_probe(device_t dev)
|
||||||
{
|
{
|
||||||
struct bhnd_nvram_io *io;
|
struct bcm_platform *bp;
|
||||||
bhnd_nvram_data_class *cls;
|
|
||||||
const char *cls_desc;
|
|
||||||
char *dname;
|
|
||||||
char *desc;
|
|
||||||
|
|
||||||
/* Locate a usable CFE device */
|
/* Fetch platform NVRAM I/O context */
|
||||||
io = bhnd_nvram_find_cfedev(dev, &dname, &cls);
|
bp = bcm_get_platform();
|
||||||
if (io == NULL)
|
if (bp->nvram_io == NULL)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
bhnd_nvram_io_free(io);
|
|
||||||
|
|
||||||
/* Format the device description */
|
KASSERT(bp->nvram_cls != NULL, ("missing NVRAM class"));
|
||||||
cls_desc = bhnd_nvram_data_class_desc(cls);
|
|
||||||
asprintf(&desc, M_DEVBUF, "%s CFE %s", cls_desc, dname);
|
/* Set the device description */
|
||||||
if (desc != NULL) {
|
device_set_desc(dev, bhnd_nvram_data_class_desc(bp->nvram_cls));
|
||||||
device_set_desc_copy(dev, desc);
|
|
||||||
free(desc, M_DEVBUF);
|
|
||||||
} else {
|
|
||||||
device_set_desc(dev, cls_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Refuse wildcard attachments */
|
/* Refuse wildcard attachments */
|
||||||
return (BUS_PROBE_NOWILDCARD);
|
return (BUS_PROBE_NOWILDCARD);
|
||||||
@ -133,25 +104,19 @@ bhnd_nvram_cfe_probe(device_t dev)
|
|||||||
static int
|
static int
|
||||||
bhnd_nvram_cfe_attach(device_t dev)
|
bhnd_nvram_cfe_attach(device_t dev)
|
||||||
{
|
{
|
||||||
|
struct bcm_platform *bp;
|
||||||
struct bhnd_nvram_cfe_softc *sc;
|
struct bhnd_nvram_cfe_softc *sc;
|
||||||
bhnd_nvram_data_class *cls;
|
|
||||||
struct bhnd_nvram_io *io;
|
|
||||||
char *dname;
|
|
||||||
int error;
|
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 = device_get_softc(dev);
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
|
|
||||||
/* Locate NVRAM device via CFE */
|
error = bhnd_nvram_store_parse_new(&sc->store, bp->nvram_io,
|
||||||
io = bhnd_nvram_find_cfedev(dev, &dname, &cls);
|
bp->nvram_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);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
@ -201,79 +166,79 @@ bhnd_nvram_cfe_setvar(device_t dev, const char *name, const void *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find, open, identify, and return an I/O context mapping our
|
* Find, open, identify, and initialize an I/O context mapping the CFE NVRAM
|
||||||
* CFE NVRAM device.
|
* device.
|
||||||
*
|
*
|
||||||
* @param dev bhnd_nvram_cfe device.
|
* @param[out] iocfe On success, an I/O context mapping the CFE NVRAM
|
||||||
* @param[out] dname On success, the CFE device name.
|
* device.
|
||||||
* @param[out] cls On success, the identified NVRAM data format
|
* @param[out] cls On success, the identified NVRAM data format
|
||||||
* class.
|
* class.
|
||||||
*
|
*
|
||||||
* @retval non-NULL success. the caller inherits ownership of the returned
|
* @retval 0 success. the caller inherits ownership of @p iocfe.
|
||||||
* NVRAM I/O context.
|
* @retval non-zero if no usable CFE NVRAM device can be found, a standard
|
||||||
* @retval NULL if no usable CFE NVRAM device could be found.
|
* unix error will be returned.
|
||||||
*/
|
*/
|
||||||
static struct bhnd_nvram_io *
|
int
|
||||||
bhnd_nvram_find_cfedev(device_t dev, char **dname, bhnd_nvram_data_class **cls)
|
bcm_nvram_find_cfedev(struct bcm_nvram_iocfe *iocfe,
|
||||||
|
bhnd_nvram_data_class **cls)
|
||||||
{
|
{
|
||||||
struct bhnd_nvram_io *io;
|
char *dname;
|
||||||
int devinfo;
|
int devinfo;
|
||||||
int error, result;
|
int error, result;
|
||||||
|
|
||||||
for (u_int i = 0; i < nitems(nvram_cfe_fmts); i++) {
|
for (u_int i = 0; i < nitems(nvram_cfe_fmts); i++) {
|
||||||
*cls = nvram_cfe_fmts[i];
|
*cls = nvram_cfe_fmts[i];
|
||||||
|
|
||||||
for (u_int j = 0; j < nitems(nvram_cfe_devs); j++) {
|
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? */
|
/* Does the device exist? */
|
||||||
if ((devinfo = cfe_getdevinfo(*dname)) < 0) {
|
if ((devinfo = cfe_getdevinfo(dname)) < 0) {
|
||||||
if (devinfo != CFE_ERR_DEVNOTFOUND) {
|
if (devinfo != CFE_ERR_DEVNOTFOUND) {
|
||||||
device_printf(dev, "cfe_getdevinfo(%s) "
|
BCM_ERR("cfe_getdevinfo(%s) failed: "
|
||||||
"failed: %d\n", *dname, devinfo);
|
"%d\n", dname, devinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open for reading */
|
/* Open for reading */
|
||||||
if ((error = bhnd_nvram_iocfe_new(&io, *dname)))
|
if ((error = bcm_nvram_iocfe_init(iocfe, dname)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Probe */
|
/* Probe */
|
||||||
result = bhnd_nvram_data_probe(*cls, io);
|
result = bhnd_nvram_data_probe(*cls, &iocfe->io);
|
||||||
if (result <= 0) {
|
if (result <= 0) {
|
||||||
/* Found a supporting NVRAM data class */
|
/* Found a supporting NVRAM data class */
|
||||||
return (io);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep searching */
|
/* Keep searching */
|
||||||
bhnd_nvram_io_free(io);
|
bhnd_nvram_io_free(&iocfe->io);
|
||||||
io = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
* The caller is responsible for releasing all resources held by the returned
|
||||||
* bhnd_nvram_io_free().
|
* I/O context via bhnd_nvram_io_free().
|
||||||
*
|
*
|
||||||
* @param[out] io On success, a valid I/O context for @p dname.
|
* @param[out] io On success, will be initialized as an I/O context for
|
||||||
* @param dname The name of the CFE device to be opened for reading.
|
* CFE device @p dname.
|
||||||
|
* @param dname The name of the CFE device to be opened for reading.
|
||||||
*
|
*
|
||||||
* @retval 0 success.
|
* @retval 0 success.
|
||||||
* @retval non-zero if opening @p dname otherwise fails, a standard unix error
|
* @retval non-zero if opening @p dname otherwise fails, a standard unix
|
||||||
* will be returned.
|
* error will be returned.
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
nvram_info_t nvram_info;
|
||||||
int cerr, devinfo, dtype, rlen;
|
int cerr, devinfo, dtype, rlen;
|
||||||
int64_t nv_offset;
|
int64_t nv_offset;
|
||||||
@ -281,7 +246,6 @@ bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname)
|
|||||||
bool req_blk_erase;
|
bool req_blk_erase;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
iocfe = malloc(sizeof(*iocfe), M_DEVBUF, M_WAITOK);
|
|
||||||
iocfe->io.iops = &bhnd_nvram_iocfe_ops;
|
iocfe->io.iops = &bhnd_nvram_iocfe_ops;
|
||||||
iocfe->dname = dname;
|
iocfe->dname = dname;
|
||||||
|
|
||||||
@ -290,8 +254,7 @@ bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname)
|
|||||||
if (iocfe->fd <= 0) {
|
if (iocfe->fd <= 0) {
|
||||||
IOCFE_LOG(iocfe, "cfe_open() failed: %d\n", iocfe->fd);
|
IOCFE_LOG(iocfe, "cfe_open() failed: %d\n", iocfe->fd);
|
||||||
|
|
||||||
error = ENXIO;
|
return (ENXIO);
|
||||||
goto failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to fetch device info */
|
/* Try to fetch device info */
|
||||||
@ -374,32 +337,29 @@ bhnd_nvram_iocfe_new(struct bhnd_nvram_io **io, char *dname)
|
|||||||
iocfe->size = nv_size;
|
iocfe->size = nv_size;
|
||||||
iocfe->req_blk_erase = req_blk_erase;
|
iocfe->req_blk_erase = req_blk_erase;
|
||||||
|
|
||||||
*io = &iocfe->io;
|
|
||||||
return (CFE_OK);
|
return (CFE_OK);
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
if (iocfe->fd >= 0)
|
if (iocfe->fd >= 0)
|
||||||
cfe_close(iocfe->fd);
|
cfe_close(iocfe->fd);
|
||||||
|
|
||||||
free(iocfe, M_DEVBUF);
|
|
||||||
|
|
||||||
*io = NULL;
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bhnd_nvram_iocfe_free(struct bhnd_nvram_io *io)
|
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);
|
cfe_close(iocfe->fd);
|
||||||
free(io, M_DEVBUF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
bhnd_nvram_iocfe_getsize(struct bhnd_nvram_io *io)
|
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);
|
return (iocfe->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,12 +398,12 @@ static int
|
|||||||
bhnd_nvram_iocfe_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
bhnd_nvram_iocfe_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||||
size_t nbytes)
|
size_t nbytes)
|
||||||
{
|
{
|
||||||
struct bhnd_nvram_iocfe *iocfe;
|
struct bcm_nvram_iocfe *iocfe;
|
||||||
size_t remain;
|
size_t remain;
|
||||||
int64_t cfe_offset;
|
int64_t cfe_offset;
|
||||||
int nr, nreq;
|
int nr, nreq;
|
||||||
|
|
||||||
iocfe = (struct bhnd_nvram_iocfe *)io;
|
iocfe = (struct bcm_nvram_iocfe *)io;
|
||||||
|
|
||||||
/* Determine (and validate) the base CFE offset */
|
/* Determine (and validate) the base CFE offset */
|
||||||
#if (SIZE_MAX > INT64_MAX)
|
#if (SIZE_MAX > INT64_MAX)
|
||||||
|
@ -36,8 +36,28 @@
|
|||||||
#include <sys/bus.h>
|
#include <sys/bus.h>
|
||||||
|
|
||||||
#include <dev/bhnd/nvram/bhnd_nvram.h>
|
#include <dev/bhnd/nvram/bhnd_nvram.h>
|
||||||
|
#include <dev/bhnd/nvram/bhnd_nvram_iovar.h>
|
||||||
#include <dev/bhnd/nvram/bhnd_nvram_store.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. */
|
/** bhnd_nvram_cfe driver instance state. */
|
||||||
struct bhnd_nvram_cfe_softc {
|
struct bhnd_nvram_cfe_softc {
|
||||||
device_t dev;
|
device_t dev;
|
||||||
|
Loading…
Reference in New Issue
Block a user