Merge ^/head r309170 through r309212.
This commit is contained in:
commit
d6d16831c5
@ -142,6 +142,8 @@ OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_
|
||||
OLD_DIRS+=usr/lib/clang/3.9.0/lib/freebsd
|
||||
OLD_DIRS+=usr/lib/clang/3.9.0/lib
|
||||
OLD_DIRS+=usr/lib/clang/3.9.0
|
||||
# 20161127: Remove vm_page_cache(9)
|
||||
OLD_FILES+=usr/share/man/man9/vm_page_cache.9.gz
|
||||
# 20161124: new clang import which bumps version from 3.8.0 to 3.9.0.
|
||||
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/allocator_interface.h
|
||||
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/asan_interface.h
|
||||
|
@ -1,3 +1,3 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#define FREEBSD_CC_VERSION 1200004
|
||||
#define FREEBSD_CC_VERSION 1200005
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 18, 2015
|
||||
.Dd November 25, 2016
|
||||
.Dt MMAP 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -189,6 +189,8 @@ this option any VM pages you dirty may be flushed to disk every so often
|
||||
(every 30-60 seconds usually) which can create performance problems if you
|
||||
do not need that to occur (such as when you are using shared file-backed
|
||||
mmap regions for IPC purposes).
|
||||
Dirty data will be flushed automatically when all mappings of an object are
|
||||
removed and all descriptors referencing the object are closed.
|
||||
Note that VM/file system coherency is
|
||||
maintained whether you use
|
||||
.Dv MAP_NOSYNC
|
||||
|
@ -352,7 +352,6 @@ MAN= accept_filter.9 \
|
||||
vm_page_alloc.9 \
|
||||
vm_page_bits.9 \
|
||||
vm_page_busy.9 \
|
||||
vm_page_cache.9 \
|
||||
vm_page_deactivate.9 \
|
||||
vm_page_dontneed.9 \
|
||||
vm_page_aflag.9 \
|
||||
|
@ -1,51 +0,0 @@
|
||||
.\"
|
||||
.\" Copyright (C) 2001 Chad David <davidc@acns.ab.ca>. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice(s), this list of conditions and the following disclaimer as
|
||||
.\" the first lines of this file unmodified other than the possible
|
||||
.\" addition of one or more copyright notices.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice(s), this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
.\" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
.\" DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 24, 2001
|
||||
.Dt VM_PAGE_CACHE 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm vm_page_cache
|
||||
.Nd "move a page onto the cache queue"
|
||||
.Sh SYNOPSIS
|
||||
.In sys/param.h
|
||||
.In vm/vm.h
|
||||
.In vm/vm_page.h
|
||||
.Ft void
|
||||
.Fn vm_page_cache "vm_page_t m"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn vm_page_cache
|
||||
function moves a page onto the cache queue,
|
||||
and removes any protection that may be set on the page.
|
||||
If the page is busy, wired or unmanaged then the move
|
||||
to the cache queue will fail.
|
||||
If the page is dirty the system will panic.
|
||||
.Sh AUTHORS
|
||||
This manual page was written by
|
||||
.An Chad David Aq Mt davidc@acns.ab.ca .
|
@ -78,6 +78,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define CH1_CLK_DIV_RATIO_M_SHIFT 0
|
||||
|
||||
#define TCON_PLLREF 3000000ULL
|
||||
#define TCON_PLLREF_FRAC1 297000000ULL
|
||||
#define TCON_PLLREF_FRAC2 270000000ULL
|
||||
#define TCON_PLL_M_MIN 1
|
||||
#define TCON_PLL_M_MAX 15
|
||||
#define TCON_PLL_N_MIN 9
|
||||
@ -290,7 +292,7 @@ aw_lcdclk_recalc_freq(struct clknode *clk, uint64_t *freq)
|
||||
}
|
||||
|
||||
static void
|
||||
calc_tcon_pll(uint64_t fin, uint64_t fout, uint32_t *pm, uint32_t *pn)
|
||||
calc_tcon_pll_integer(uint64_t fin, uint64_t fout, uint32_t *pm, uint32_t *pn)
|
||||
{
|
||||
int64_t diff, fcur, best;
|
||||
int m, n;
|
||||
@ -309,15 +311,87 @@ calc_tcon_pll(uint64_t fin, uint64_t fout, uint32_t *pm, uint32_t *pn)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
calc_tcon_pll_fractional(uint64_t fin, uint64_t fout, int *clk_div)
|
||||
{
|
||||
int m;
|
||||
|
||||
/* Test for 1X match */
|
||||
for (m = TCON_PLL_M_MIN; m <= TCON_PLL_M_MAX; m++) {
|
||||
if (fout == (fin / m)) {
|
||||
*clk_div = m;
|
||||
return (CH0_CLK_SRC_SEL_PLL3_1X);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test for 2X match */
|
||||
for (m = TCON_PLL_M_MIN; m <= TCON_PLL_M_MAX; m++) {
|
||||
if (fout == ((fin * 2) / m)) {
|
||||
*clk_div = m;
|
||||
return (CH0_CLK_SRC_SEL_PLL3_2X);
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
calc_tcon_pll(uint64_t fin, uint64_t fout, uint64_t *pll_freq, int *tcon_pll_div)
|
||||
{
|
||||
uint32_t m, m2, n, n2;
|
||||
uint64_t fsingle, fdouble;
|
||||
int src_sel;
|
||||
bool dbl;
|
||||
|
||||
/* Test fractional freq first */
|
||||
src_sel = calc_tcon_pll_fractional(TCON_PLLREF_FRAC1, fout,
|
||||
tcon_pll_div);
|
||||
if (src_sel != -1) {
|
||||
*pll_freq = TCON_PLLREF_FRAC1;
|
||||
return src_sel;
|
||||
}
|
||||
src_sel = calc_tcon_pll_fractional(TCON_PLLREF_FRAC2, fout,
|
||||
tcon_pll_div);
|
||||
if (src_sel != -1) {
|
||||
*pll_freq = TCON_PLLREF_FRAC2;
|
||||
return src_sel;
|
||||
}
|
||||
|
||||
m = n = m2 = n2 = 0;
|
||||
dbl = false;
|
||||
|
||||
/* Find the frequency closes to the target dot clock, using
|
||||
* both 1X and 2X PLL inputs as possible candidates.
|
||||
*/
|
||||
calc_tcon_pll_integer(TCON_PLLREF, fout, &m, &n);
|
||||
calc_tcon_pll_integer(TCON_PLLREF * 2, fout, &m2, &n2);
|
||||
|
||||
fsingle = m ? (n * TCON_PLLREF) / m : 0;
|
||||
fdouble = m2 ? (n2 * TCON_PLLREF * 2) / m2 : 0;
|
||||
|
||||
if (fdouble > fsingle) {
|
||||
dbl = true;
|
||||
m = m2;
|
||||
n = n2;
|
||||
}
|
||||
|
||||
/* Set desired parent frequency */
|
||||
*pll_freq = n * TCON_PLLREF;
|
||||
*tcon_pll_div = m;
|
||||
|
||||
/* Return the desired source clock */
|
||||
return (dbl ? CH0_CLK_SRC_SEL_PLL3_2X :
|
||||
CH0_CLK_SRC_SEL_PLL3_1X);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
int flags, int *stop)
|
||||
{
|
||||
struct aw_lcdclk_softc *sc;
|
||||
uint32_t val, m, m2, n, n2, src_sel;
|
||||
uint64_t fsingle, fdouble;
|
||||
int error;
|
||||
bool dbl;
|
||||
uint64_t pll_freq;
|
||||
uint32_t val, src_sel;
|
||||
int error, tcon_pll_div;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
@ -329,26 +403,7 @@ aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
if (sc->id != CLK_IDX_CH1_SCLK2)
|
||||
return (ENXIO);
|
||||
|
||||
m = n = m2 = n2 = 0;
|
||||
dbl = false;
|
||||
|
||||
/* Find the frequency closes to the target dot clock, using
|
||||
* both 1X and 2X PLL inputs as possible candidates.
|
||||
*/
|
||||
calc_tcon_pll(TCON_PLLREF, *fout, &m, &n);
|
||||
calc_tcon_pll(TCON_PLLREF * 2, *fout, &m2, &n2);
|
||||
|
||||
fsingle = m ? (n * TCON_PLLREF) / m : 0;
|
||||
fdouble = m2 ? (n2 * TCON_PLLREF * 2) / m2 : 0;
|
||||
|
||||
if (fdouble > fsingle) {
|
||||
dbl = true;
|
||||
m = m2;
|
||||
n = n2;
|
||||
}
|
||||
|
||||
src_sel = dbl ? CH0_CLK_SRC_SEL_PLL3_2X :
|
||||
CH0_CLK_SRC_SEL_PLL3_1X;
|
||||
src_sel = calc_tcon_pll(fin, *fout, &pll_freq, &tcon_pll_div);
|
||||
|
||||
/* Switch parent clock if necessary */
|
||||
if (src_sel != clknode_get_parent_idx(clk)) {
|
||||
@ -357,10 +412,8 @@ aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Set desired parent frequency */
|
||||
fin = n * TCON_PLLREF;
|
||||
|
||||
error = clknode_set_freq(clknode_get_parent(clk), fin, 0, 0);
|
||||
error = clknode_set_freq(clknode_get_parent(clk), pll_freq,
|
||||
0, 0);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
@ -369,7 +422,7 @@ aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
return (error);
|
||||
|
||||
/* Fetch new input frequency */
|
||||
error = clknode_get_freq(clknode_get_parent(clk), &fin);
|
||||
error = clknode_get_freq(clknode_get_parent(clk), &pll_freq);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
@ -377,11 +430,11 @@ aw_lcdclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
DEVICE_LOCK(sc);
|
||||
LCDCLK_READ(sc, &val);
|
||||
val &= ~CH1_CLK_DIV_RATIO_M;
|
||||
val |= ((m - 1) << CH1_CLK_DIV_RATIO_M_SHIFT);
|
||||
val |= ((tcon_pll_div - 1) << CH1_CLK_DIV_RATIO_M_SHIFT);
|
||||
LCDCLK_WRITE(sc, val);
|
||||
DEVICE_UNLOCK(sc);
|
||||
|
||||
*fout = fin / m;
|
||||
*fout = pll_freq / tcon_pll_div;
|
||||
*stop = 1;
|
||||
|
||||
break;
|
||||
|
@ -482,11 +482,20 @@ a10_pll3_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
|
||||
{
|
||||
uint32_t val, m, mode, func;
|
||||
|
||||
m = *fout / A10_PLL3_REF_FREQ;
|
||||
|
||||
mode = A10_PLL3_MODE_SEL_INT;
|
||||
func = 0;
|
||||
*fout = m * A10_PLL3_REF_FREQ;
|
||||
if (*fout == 297000000) {
|
||||
func = A10_PLL3_FUNC_SET_297MHZ;
|
||||
mode = A10_PLL3_MODE_SEL_FRACT;
|
||||
m = 0;
|
||||
} else if (*fout == 270000000) {
|
||||
func = A10_PLL3_FUNC_SET_270MHZ;
|
||||
mode = A10_PLL3_MODE_SEL_FRACT;
|
||||
m = 0;
|
||||
} else {
|
||||
mode = A10_PLL3_MODE_SEL_INT;
|
||||
func = 0;
|
||||
m = *fout / A10_PLL3_REF_FREQ;
|
||||
*fout = m * A10_PLL3_REF_FREQ;
|
||||
}
|
||||
|
||||
DEVICE_LOCK(sc);
|
||||
PLL_READ(sc, &val);
|
||||
|
@ -298,7 +298,7 @@
|
||||
reg = <0x00000001>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ethernet {
|
||||
ethernet: ethernet {
|
||||
compatible = "net,ethernet",
|
||||
"usb,device";
|
||||
reg = <0x00000001>;
|
||||
@ -386,6 +386,7 @@
|
||||
|
||||
aliases {
|
||||
uart0 = &uart0;
|
||||
ethernet0 = ðernet;
|
||||
};
|
||||
|
||||
chosen {
|
||||
|
@ -315,7 +315,7 @@
|
||||
reg = <0x00000001>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ethernet {
|
||||
ethernet: ethernet {
|
||||
compatible = "net,ethernet",
|
||||
"usb,device";
|
||||
reg = <0x00000001>;
|
||||
@ -397,6 +397,7 @@
|
||||
|
||||
aliases {
|
||||
uart0 = &uart0;
|
||||
ethernet0 = ðernet;
|
||||
};
|
||||
|
||||
chosen {
|
||||
|
@ -1220,14 +1220,22 @@ dev/bhnd/cores/pmu/bhnd_pmu.c optional bhnd
|
||||
dev/bhnd/cores/pmu/bhnd_pmu_core.c optional bhnd
|
||||
dev/bhnd/cores/pmu/bhnd_pmu_if.m optional bhnd
|
||||
dev/bhnd/cores/pmu/bhnd_pmu_subr.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_common.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_cfe.c optional bhnd siba_nexus cfe | \
|
||||
bhnd bcma_nexus cfe
|
||||
dev/bhnd/nvram/bhnd_nvram_data.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_data_bcm.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_data_btxt.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_data_sprom.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_data_tlv.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_if.m optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_parser.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_io.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_iobuf.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_iores.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_store.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_subr.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value_fmts.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value_prf.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_sprom.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_sprom_parser.c optional bhnd
|
||||
dev/bhnd/siba/siba.c optional siba bhnd
|
||||
dev/bhnd/siba/siba_bhndb.c optional siba bhnd bhndb
|
||||
dev/bhnd/siba/siba_erom.c optional siba bhnd
|
||||
|
@ -1057,7 +1057,8 @@ bhnd_nvram_getvar_str(device_t dev, const char *name, char *buf, size_t len,
|
||||
int error;
|
||||
|
||||
larg = len;
|
||||
error = bhnd_nvram_getvar(dev, name, buf, &larg, BHND_NVRAM_TYPE_CSTR);
|
||||
error = bhnd_nvram_getvar(dev, name, buf, &larg,
|
||||
BHND_NVRAM_TYPE_STRING);
|
||||
if (rlen != NULL)
|
||||
*rlen = larg;
|
||||
|
||||
|
@ -1,189 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* BHND CFE NVRAM driver.
|
||||
*
|
||||
* Provides access to device NVRAM via CFE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
|
||||
#include <dev/cfe/cfe_api.h>
|
||||
#include <dev/cfe/cfe_error.h>
|
||||
#include <dev/cfe/cfe_ioctl.h>
|
||||
|
||||
#include "bhnd_nvram_if.h"
|
||||
|
||||
#include "bhnd_nvramvar.h"
|
||||
|
||||
/**
|
||||
* Default bhnd_nvram driver implementation of DEVICE_PROBE().
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "Broadcom NVRAM");
|
||||
|
||||
/* Refuse wildcard attachments */
|
||||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call from subclass DEVICE_ATTACH() implementations to handle
|
||||
* device attachment.
|
||||
*
|
||||
* @param dev BHND NVRAM device.
|
||||
* @param data NVRAM data to be copied and parsed. No reference to data
|
||||
* will be held after return.
|
||||
* @param size Size of @p data, in bytes.
|
||||
* @param fmt NVRAM format.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_attach(device_t dev, void *data, size_t size, bhnd_nvram_format fmt)
|
||||
{
|
||||
struct bhnd_nvram_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
/* Initialize NVRAM parser */
|
||||
error = bhnd_nvram_parser_init(&sc->nvram, dev, data, size, fmt);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Initialize mutex */
|
||||
BHND_NVRAM_LOCK_INIT(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhnd_nvram driver implementation of DEVICE_RESUME().
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_resume(device_t dev)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhnd_nvram driver implementation of DEVICE_SUSPEND().
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_suspend(device_t dev)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhnd_nvram driver implementation of DEVICE_DETACH().
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_detach(device_t dev)
|
||||
{
|
||||
struct bhnd_nvram_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
bhnd_nvram_parser_fini(&sc->nvram);
|
||||
BHND_NVRAM_LOCK_DESTROY(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhnd_nvram driver implementation of BHND_NVRAM_GETVAR().
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_getvar_method(device_t dev, const char *name, void *buf, size_t *len,
|
||||
bhnd_nvram_type type)
|
||||
{
|
||||
struct bhnd_nvram_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
BHND_NVRAM_LOCK(sc);
|
||||
error = bhnd_nvram_parser_getvar(&sc->nvram, name, buf, len, type);
|
||||
BHND_NVRAM_UNLOCK(sc);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhnd_nvram driver implementation of BHND_NVRAM_SETVAR().
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_setvar_method(device_t dev, const char *name, const void *buf,
|
||||
size_t len, bhnd_nvram_type type)
|
||||
{
|
||||
struct bhnd_nvram_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
BHND_NVRAM_LOCK(sc);
|
||||
error = bhnd_nvram_parser_setvar(&sc->nvram, name, buf, len, type);
|
||||
BHND_NVRAM_UNLOCK(sc);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static device_method_t bhnd_nvram_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, bhnd_nvram_probe),
|
||||
DEVMETHOD(device_resume, bhnd_nvram_resume),
|
||||
DEVMETHOD(device_suspend, bhnd_nvram_suspend),
|
||||
DEVMETHOD(device_detach, bhnd_nvram_detach),
|
||||
|
||||
/* NVRAM interface */
|
||||
DEVMETHOD(bhnd_nvram_getvar, bhnd_nvram_getvar_method),
|
||||
DEVMETHOD(bhnd_nvram_setvar, bhnd_nvram_setvar_method),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(bhnd_nvram, bhnd_nvram_driver, bhnd_nvram_methods, sizeof(struct bhnd_nvram_softc));
|
@ -32,11 +32,17 @@
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/types.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/**
|
||||
* NVRAM data sources supported by bhnd(4) devices.
|
||||
*/
|
||||
typedef enum {
|
||||
|
||||
BHND_NVRAM_SRC_OTP, /**< On-chip one-time-programmable
|
||||
* memory. */
|
||||
|
||||
@ -67,50 +73,52 @@ typedef enum {
|
||||
*/
|
||||
} bhnd_nvram_src;
|
||||
|
||||
/** Supported NVRAM formats. */
|
||||
/**
|
||||
* NVRAM data types.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* All primitive (non-array) constants should be representable as a 4-bit
|
||||
* integer (e.g. 0-15) to support SPROM_OPCODE_TYPE_IMM encoding as used by
|
||||
* nvram_map_gen.awk.
|
||||
*/
|
||||
typedef enum {
|
||||
BHND_NVRAM_FMT_BCM = 0, /**< Broadcom NUL-delimited key=value pairs */
|
||||
BHND_NVRAM_FMT_TLV = 1, /**< CFE TLV encoding, as used on WGT634U */
|
||||
BHND_NVRAM_FMT_BTXT = 2, /**< Broadcom board text file. This is used
|
||||
to provide external NVRAM data for some
|
||||
fullmac WiFi devices. */
|
||||
BHND_NVRAM_FMT_SPROM = 3, /**< SPROM/OTP-specific encoding used by
|
||||
Broadcom network adapters */
|
||||
BHND_NVRAM_FMT_CIS = 4, /**< A mostly CIS-compatible encoding used
|
||||
on some Broadcom network adapters */
|
||||
BHND_NVRAM_FMT_UNKNOWN = 5 /**< Unknown or unrecognized format */
|
||||
} bhnd_nvram_format;
|
||||
BHND_NVRAM_TYPE_UINT8 = 0, /**< unsigned 8-bit integer */
|
||||
BHND_NVRAM_TYPE_UINT16 = 1, /**< unsigned 16-bit integer */
|
||||
BHND_NVRAM_TYPE_UINT32 = 2, /**< unsigned 32-bit integer */
|
||||
BHND_NVRAM_TYPE_UINT64 = 3, /**< signed 64-bit integer */
|
||||
BHND_NVRAM_TYPE_INT8 = 4, /**< signed 8-bit integer */
|
||||
BHND_NVRAM_TYPE_INT16 = 5, /**< signed 16-bit integer */
|
||||
BHND_NVRAM_TYPE_INT32 = 6, /**< signed 32-bit integer */
|
||||
BHND_NVRAM_TYPE_INT64 = 7, /**< signed 64-bit integer */
|
||||
BHND_NVRAM_TYPE_CHAR = 8, /**< ASCII/UTF-8 character */
|
||||
BHND_NVRAM_TYPE_STRING = 9, /**< ASCII/UTF-8 NUL-terminated
|
||||
string */
|
||||
|
||||
/* 10-15 reserved for primitive (non-array) types */
|
||||
|
||||
/** bhnd_nvram_type bit flags */
|
||||
enum {
|
||||
BHND_NVRAM_TF_SIGNED = (1<<7),
|
||||
};
|
||||
|
||||
#define BHND_NVRAM_TYPE_ID_MASK 0xF
|
||||
#define BHND_NVRAM_TYPE_FLAGS_MASK 0x70
|
||||
|
||||
#define BHND_NVRAM_TYPE_ID(_id, _flags) \
|
||||
(((_id) & BHND_NVRAM_TYPE_ID_MASK) | \
|
||||
((_flags) & BHND_NVRAM_TYPE_FLAGS_MASK))
|
||||
|
||||
/** Supported NVRAM data types */
|
||||
typedef enum {
|
||||
BHND_NVRAM_TYPE_UINT8 = BHND_NVRAM_TYPE_ID(0, 0), /**< unsigned 8-bit integer */
|
||||
BHND_NVRAM_TYPE_UINT16 = BHND_NVRAM_TYPE_ID(1, 0), /**< unsigned 16-bit integer */
|
||||
BHND_NVRAM_TYPE_UINT32 = BHND_NVRAM_TYPE_ID(2, 0), /**< unsigned 32-bit integer */
|
||||
BHND_NVRAM_TYPE_INT8 = BHND_NVRAM_TYPE_ID(4, BHND_NVRAM_TF_SIGNED), /**< signed 8-bit integer */
|
||||
BHND_NVRAM_TYPE_INT16 = BHND_NVRAM_TYPE_ID(5, BHND_NVRAM_TF_SIGNED), /**< signed 16-bit integer */
|
||||
BHND_NVRAM_TYPE_INT32 = BHND_NVRAM_TYPE_ID(6, BHND_NVRAM_TF_SIGNED), /**< signed 32-bit integer */
|
||||
BHND_NVRAM_TYPE_CHAR = BHND_NVRAM_TYPE_ID(7, BHND_NVRAM_TF_SIGNED), /**< ASCII character */
|
||||
BHND_NVRAM_TYPE_CSTR = BHND_NVRAM_TYPE_ID(8, 0), /**< NUL-terminated C string */
|
||||
BHND_NVRAM_TYPE_UINT8_ARRAY = 16, /**< array of uint8 integers */
|
||||
BHND_NVRAM_TYPE_UINT16_ARRAY = 17, /**< array of uint16 integers */
|
||||
BHND_NVRAM_TYPE_UINT32_ARRAY = 18, /**< array of uint32 integers */
|
||||
BHND_NVRAM_TYPE_UINT64_ARRAY = 19, /**< array of uint64 integers */
|
||||
BHND_NVRAM_TYPE_INT8_ARRAY = 20, /**< array of int8 integers */
|
||||
BHND_NVRAM_TYPE_INT16_ARRAY = 21, /**< array of int16 integers */
|
||||
BHND_NVRAM_TYPE_INT32_ARRAY = 22, /**< array of int32 integers */
|
||||
BHND_NVRAM_TYPE_INT64_ARRAY = 23, /**< array of int64 integers */
|
||||
BHND_NVRAM_TYPE_CHAR_ARRAY = 24, /**< array of ASCII/UTF-8
|
||||
characters */
|
||||
BHND_NVRAM_TYPE_STRING_ARRAY = 25, /**< array of ASCII/UTF-8
|
||||
NUL-terminated strings */
|
||||
} bhnd_nvram_type;
|
||||
|
||||
#undef BHND_NVRAM_TYPE_ID_MASK
|
||||
#undef BHND_NVRAM_TYPE_FLAGS_MASK
|
||||
#undef BHND_NVRAM_TYPE_ID
|
||||
const char *bhnd_nvram_string_array_next(const char *inp, size_t ilen,
|
||||
const char *prev);
|
||||
|
||||
#define BHND_NVRAM_SIGNED_TYPE(_type) \
|
||||
(((_type) & BHND_NVRAM_TF_SIGNED) == BHND_NVRAM_TF_SIGNED)
|
||||
bool bhnd_nvram_is_signed_type(bhnd_nvram_type type);
|
||||
bool bhnd_nvram_is_unsigned_type(bhnd_nvram_type type);
|
||||
bool bhnd_nvram_is_int_type(bhnd_nvram_type type);
|
||||
bool bhnd_nvram_is_array_type(bhnd_nvram_type type);
|
||||
bhnd_nvram_type bhnd_nvram_base_type(bhnd_nvram_type type);
|
||||
const char *bhnd_nvram_type_name(bhnd_nvram_type type);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_H_ */
|
||||
|
@ -1,373 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* BHND CFE NVRAM driver.
|
||||
*
|
||||
* Provides access to device NVRAM via CFE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
|
||||
#include <dev/cfe/cfe_api.h>
|
||||
#include <dev/cfe/cfe_error.h>
|
||||
#include <dev/cfe/cfe_ioctl.h>
|
||||
|
||||
#include "bhnd_nvram_if.h"
|
||||
|
||||
#include "bhnd_nvramvar.h"
|
||||
|
||||
static int nvram_open_cfedev(device_t dev, char *devname, int fd,
|
||||
int64_t *offset, uint32_t *size, bhnd_nvram_format fmt);
|
||||
static char *nvram_find_cfedev(device_t dev, int *fd, int64_t *offset,
|
||||
uint32_t *size, bhnd_nvram_format *fmt);
|
||||
|
||||
/** Known CFE NVRAM device names, in probe order. */
|
||||
static char *nvram_cfe_devs[] = {
|
||||
"nflash0.nvram", /* NAND */
|
||||
"nflash1.nvram",
|
||||
"flash0.nvram",
|
||||
"flash1.nvram",
|
||||
};
|
||||
|
||||
/** Supported CFE NVRAM formats, in probe order. */
|
||||
bhnd_nvram_format nvram_cfe_fmts[] = {
|
||||
BHND_NVRAM_FMT_BCM,
|
||||
BHND_NVRAM_FMT_TLV
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_probe(device_t dev)
|
||||
{
|
||||
char *devname;
|
||||
bhnd_nvram_format fmt;
|
||||
int64_t offset;
|
||||
uint32_t size;
|
||||
int error;
|
||||
int fd;
|
||||
|
||||
/* Defer to default driver implementation */
|
||||
if ((error = bhnd_nvram_probe(dev)) > 0)
|
||||
return (error);
|
||||
|
||||
/* Locate a usable CFE device */
|
||||
devname = nvram_find_cfedev(dev, &fd, &offset, &size, &fmt);
|
||||
if (devname == NULL)
|
||||
return (ENXIO);
|
||||
cfe_close(fd);
|
||||
|
||||
switch (fmt) {
|
||||
case BHND_NVRAM_FMT_BCM:
|
||||
device_set_desc(dev, "Broadcom NVRAM");
|
||||
break;
|
||||
case BHND_NVRAM_FMT_TLV:
|
||||
device_set_desc(dev, "Broadcom WGT634U NVRAM");
|
||||
break;
|
||||
default:
|
||||
device_printf(dev, "unknown NVRAM format: %d\n", fmt);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Refuse wildcard attachments */
|
||||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_attach(device_t dev)
|
||||
{
|
||||
char *devname;
|
||||
unsigned char *buffer;
|
||||
bhnd_nvram_format fmt;
|
||||
int64_t offset;
|
||||
uint32_t size;
|
||||
int error;
|
||||
int fd;
|
||||
|
||||
error = 0;
|
||||
buffer = NULL;
|
||||
fd = CFE_ERR;
|
||||
|
||||
/* Locate NVRAM device via CFE */
|
||||
devname = nvram_find_cfedev(dev, &fd, &offset, &size, &fmt);
|
||||
if (devname == NULL) {
|
||||
device_printf(dev, "CFE NVRAM device not found\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Copy out NVRAM buffer */
|
||||
buffer = malloc(size, M_TEMP, M_NOWAIT);
|
||||
if (buffer == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
for (size_t remain = size; remain > 0;) {
|
||||
int nr, req;
|
||||
|
||||
req = ulmin(INT_MAX, remain);
|
||||
nr = cfe_readblk(fd, size-remain, buffer+(size-remain),
|
||||
req);
|
||||
if (nr < 0) {
|
||||
device_printf(dev, "%s: cfe_readblk() failed: %d\n",
|
||||
devname, fd);
|
||||
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
remain -= nr;
|
||||
|
||||
if (nr == 0 && remain > 0) {
|
||||
device_printf(dev, "%s: cfe_readblk() unexpected EOF: "
|
||||
"%zu of %zu pending\n", devname, remain, size);
|
||||
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
device_printf(dev, "CFE %s (%#jx+%#jx)\n", devname, (uintmax_t)offset,
|
||||
(uintmax_t)size);
|
||||
|
||||
/* Delegate to default driver implementation */
|
||||
error = bhnd_nvram_attach(dev, buffer, size, fmt);
|
||||
|
||||
cleanup:
|
||||
if (buffer != NULL)
|
||||
free(buffer, M_TEMP);
|
||||
|
||||
if (fd >= 0)
|
||||
cfe_close(fd);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify and open a CFE NVRAM device.
|
||||
*
|
||||
* @param dev bhnd_nvram_cfe device.
|
||||
* @param devname The name of the CFE device to be probed.
|
||||
* @param fd An open CFE file descriptor for @p devname.
|
||||
* @param[out] offset On success, the NVRAM data offset within @p @fd.
|
||||
* @param[out] size On success, maximum the NVRAM data size within @p fd.
|
||||
* @param fmt The expected NVRAM data format for this device.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero If probing @p devname fails, a regular unix
|
||||
* error code will be returned.
|
||||
*/
|
||||
static int
|
||||
nvram_open_cfedev(device_t dev, char *devname, int fd, int64_t *offset,
|
||||
uint32_t *size, bhnd_nvram_format fmt)
|
||||
{
|
||||
union bhnd_nvram_ident ident;
|
||||
nvram_info_t nvram_info;
|
||||
int cerr, devinfo, dtype, rlen;
|
||||
int error;
|
||||
|
||||
/* Try to fetch device info */
|
||||
if ((devinfo = cfe_getdevinfo(devname)) == CFE_ERR_DEVNOTFOUND)
|
||||
return (ENODEV);
|
||||
|
||||
if (devinfo < 0) {
|
||||
device_printf(dev, "cfe_getdevinfo() failed: %d",
|
||||
devinfo);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Verify device type */
|
||||
dtype = devinfo & CFE_DEV_MASK;
|
||||
switch (dtype) {
|
||||
case CFE_DEV_FLASH:
|
||||
case CFE_DEV_NVRAM:
|
||||
/* Valid device type */
|
||||
break;
|
||||
default:
|
||||
device_printf(dev, "%s: unknown device type %d\n",
|
||||
devname, dtype);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Try to fetch nvram info from CFE */
|
||||
cerr = cfe_ioctl(fd, IOCTL_NVRAM_GETINFO, (unsigned char *)&nvram_info,
|
||||
sizeof(nvram_info), &rlen, 0);
|
||||
if (cerr != CFE_OK && cerr != CFE_ERR_INV_COMMAND) {
|
||||
device_printf(dev, "%s: IOCTL_NVRAM_GETINFO failed: %d\n",
|
||||
devname, cerr);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Fall back on flash info.
|
||||
*
|
||||
* This is known to be required on the Asus RT-N53 (CFE 5.70.55.33,
|
||||
* BBP 1.0.37, BCM5358UB0), where IOCTL_NVRAM_GETINFO returns
|
||||
* CFE_ERR_INV_COMMAND.
|
||||
*/
|
||||
if (cerr == CFE_ERR_INV_COMMAND) {
|
||||
flash_info_t fi;
|
||||
|
||||
cerr = cfe_ioctl(fd, IOCTL_FLASH_GETINFO, (unsigned char *)&fi,
|
||||
sizeof(fi), &rlen, 0);
|
||||
|
||||
if (cerr != CFE_OK) {
|
||||
device_printf(dev, "%s: IOCTL_FLASH_GETINFO failed: "
|
||||
"%d\n", devname, cerr);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
nvram_info.nvram_eraseflg =
|
||||
!(fi.flash_flags & FLASH_FLAG_NOERASE);
|
||||
nvram_info.nvram_offset = 0x0;
|
||||
nvram_info.nvram_size = fi.flash_size;
|
||||
}
|
||||
|
||||
/* Try to read NVRAM header/format identification */
|
||||
cerr = cfe_readblk(fd, 0, (unsigned char *)&ident, sizeof(ident));
|
||||
if (cerr < 0) {
|
||||
device_printf(dev, "%s: cfe_readblk() failed: %d\n",
|
||||
devname, cerr);
|
||||
return (ENXIO);
|
||||
} else if (cerr == 0) {
|
||||
/* EOF */
|
||||
return (ENODEV);
|
||||
} else if (cerr != sizeof(ident)) {
|
||||
device_printf(dev, "%s: cfe_readblk() short read: %d\n",
|
||||
devname, cerr);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Verify expected format */
|
||||
if ((error = bhnd_nvram_parser_identify(&ident, fmt)))
|
||||
return (error);
|
||||
|
||||
/* Provide offset and size */
|
||||
switch (fmt) {
|
||||
case BHND_NVRAM_FMT_TLV:
|
||||
/* No size field is available; must assume the NVRAM data
|
||||
* consumes up to the full CFE NVRAM range */
|
||||
*offset = nvram_info.nvram_offset;
|
||||
*size = nvram_info.nvram_size;
|
||||
break;
|
||||
case BHND_NVRAM_FMT_BCM:
|
||||
if (ident.bcm.size > nvram_info.nvram_size) {
|
||||
device_printf(dev, "%s: NVRAM size %#x overruns %#x "
|
||||
"device limit\n", devname, ident.bcm.size,
|
||||
nvram_info.nvram_size);
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
*offset = nvram_info.nvram_offset;
|
||||
*size = ident.bcm.size;
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find (and open) a CFE NVRAM device.
|
||||
*
|
||||
* @param dev bhnd_nvram_cfe device.
|
||||
* @param[out] fd On success, a valid CFE file descriptor. The callee
|
||||
* is responsible for closing this file descriptor via
|
||||
* cfe_close().
|
||||
* @param[out] offset On success, the NVRAM data offset within @p @fd.
|
||||
* @param[out] size On success, maximum the NVRAM data size within @p fd.
|
||||
* @param fmt The expected NVRAM data format for this device.
|
||||
*
|
||||
* @return On success, the opened CFE device's name will be returned. On
|
||||
* error, returns NULL.
|
||||
*/
|
||||
static char *
|
||||
nvram_find_cfedev(device_t dev, int *fd, int64_t *offset,
|
||||
uint32_t *size, bhnd_nvram_format *fmt)
|
||||
{
|
||||
char *devname;
|
||||
int error;
|
||||
|
||||
for (u_int i = 0; i < nitems(nvram_cfe_fmts); i++) {
|
||||
*fmt = nvram_cfe_fmts[i];
|
||||
|
||||
for (u_int j = 0; j < nitems(nvram_cfe_devs); j++) {
|
||||
devname = nvram_cfe_devs[j];
|
||||
|
||||
/* Open for reading */
|
||||
*fd = cfe_open(devname);
|
||||
if (*fd == CFE_ERR_DEVNOTFOUND) {
|
||||
continue;
|
||||
} else if (*fd < 0) {
|
||||
device_printf(dev, "%s: cfe_open() failed: "
|
||||
"%d\n", devname, *fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Probe */
|
||||
error = nvram_open_cfedev(dev, devname, *fd, offset,
|
||||
size, *fmt);
|
||||
if (error == 0)
|
||||
return (devname);
|
||||
|
||||
/* Keep searching */
|
||||
devname = NULL;
|
||||
cfe_close(*fd);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static device_method_t bhnd_nvram_cfe_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, bhnd_nvram_cfe_probe),
|
||||
DEVMETHOD(device_attach, bhnd_nvram_cfe_attach),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(bhnd_nvram, bhnd_nvram_cfe, bhnd_nvram_cfe_methods,
|
||||
sizeof(struct bhnd_nvram_softc), bhnd_nvram_driver);
|
||||
EARLY_DRIVER_MODULE(bhnd_nvram_cfe, nexus, bhnd_nvram_cfe,
|
||||
bhnd_nvram_devclass, NULL, NULL, BUS_PASS_BUS + BUS_PASS_ORDER_EARLY);
|
@ -1,661 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/hash.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/_inttypes.h>
|
||||
|
||||
#include "bhnd_nvram_common.h"
|
||||
|
||||
#include "bhnd_nvram_map_data.h"
|
||||
|
||||
/*
|
||||
* Common NVRAM/SPROM support, including NVRAM variable map
|
||||
* lookup.
|
||||
*/
|
||||
|
||||
MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data");
|
||||
|
||||
/*
|
||||
* CRC-8 lookup table used to checksum SPROM and NVRAM data via
|
||||
* bhnd_nvram_crc8().
|
||||
*
|
||||
* Generated with following parameters:
|
||||
* polynomial: CRC-8 (x^8 + x^7 + x^6 + x^4 + x^2 + 1)
|
||||
* reflected bits: false
|
||||
* reversed: true
|
||||
*/
|
||||
const uint8_t bhnd_nvram_crc8_tab[] = {
|
||||
0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b, 0x4a, 0xbd, 0xf3,
|
||||
0x04, 0x6f, 0x98, 0xd6, 0x21, 0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46,
|
||||
0x08, 0xff, 0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5, 0x7f,
|
||||
0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14, 0x35, 0xc2, 0x8c, 0x7b,
|
||||
0x10, 0xe7, 0xa9, 0x5e, 0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77,
|
||||
0x80, 0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca, 0xfe, 0x09,
|
||||
0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95, 0xb4, 0x43, 0x0d, 0xfa, 0x91,
|
||||
0x66, 0x28, 0xdf, 0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01,
|
||||
0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b, 0x81, 0x76, 0x38,
|
||||
0xcf, 0xa4, 0x53, 0x1d, 0xea, 0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19,
|
||||
0x57, 0xa0, 0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e, 0x5f,
|
||||
0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34, 0xab, 0x5c, 0x12, 0xe5,
|
||||
0x8e, 0x79, 0x37, 0xc0, 0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d,
|
||||
0x8a, 0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54, 0x75, 0x82,
|
||||
0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e, 0xd4, 0x23, 0x6d, 0x9a, 0xf1,
|
||||
0x06, 0x48, 0xbf, 0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5,
|
||||
0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b, 0x0a, 0xfd, 0xb3,
|
||||
0x44, 0x2f, 0xd8, 0x96, 0x61, 0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87,
|
||||
0xc9, 0x3e, 0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74, 0xc1,
|
||||
0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa, 0x8b, 0x7c, 0x32, 0xc5,
|
||||
0xae, 0x59, 0x17, 0xe0, 0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6,
|
||||
0x41, 0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b, 0xbe, 0x49,
|
||||
0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5, 0xf4, 0x03, 0x4d, 0xba, 0xd1,
|
||||
0x26, 0x68, 0x9f
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the size of type @p type, or 0 if @p type has a variable width
|
||||
* (e.g. a C string).
|
||||
*
|
||||
* @param type NVRAM data type.
|
||||
* @result the byte width of @p type.
|
||||
*/
|
||||
size_t
|
||||
bhnd_nvram_type_width(bhnd_nvram_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
return (sizeof(uint8_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
return (sizeof(uint16_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
return (sizeof(uint32_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_CSTR:
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Quiesce gcc4.2 */
|
||||
panic("bhnd nvram type %u unknown", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the format string to use when printing @p type with @p sfmt
|
||||
*
|
||||
* @param type The value type being printed.
|
||||
* @param sfmt The string format required for @p type.
|
||||
* @param elem_num The element index being printed. If this is the first
|
||||
* value in an array of elements, the index would be 0, the next would be 1,
|
||||
* and so on.
|
||||
*
|
||||
* @retval non-NULL A valid printf format string.
|
||||
* @retval NULL If no format string is available for @p type and @p sfmt.
|
||||
*/
|
||||
const char *
|
||||
bhnd_nvram_type_fmt(bhnd_nvram_type type, bhnd_nvram_sfmt sfmt,
|
||||
size_t elem_num)
|
||||
{
|
||||
size_t width;
|
||||
|
||||
width = bhnd_nvram_type_width(type);
|
||||
|
||||
/* Sanity-check the type width */
|
||||
switch (width) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Special-cased string formats */
|
||||
switch (sfmt) {
|
||||
case BHND_NVRAM_SFMT_LEDDC:
|
||||
/* If this is the first element, use the 0x-prefixed
|
||||
* SFMT_HEX */
|
||||
if (elem_num == 0)
|
||||
sfmt = BHND_NVRAM_SFMT_HEX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return the format string */
|
||||
switch (sfmt) {
|
||||
case BHND_NVRAM_SFMT_MACADDR:
|
||||
switch (width) {
|
||||
case 1: return ("%02" PRIx8);
|
||||
}
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_SFMT_HEX:
|
||||
switch (width) {
|
||||
case 1: return ("0x%02" PRIx8);
|
||||
case 2: return ("0x%04" PRIx16);
|
||||
case 4: return ("0x%08" PRIx32);
|
||||
}
|
||||
break;
|
||||
case BHND_NVRAM_SFMT_DEC:
|
||||
if (BHND_NVRAM_SIGNED_TYPE(type)) {
|
||||
switch (width) {
|
||||
case 1: return ("%" PRId8);
|
||||
case 2: return ("%" PRId16);
|
||||
case 4: return ("%" PRId32);
|
||||
}
|
||||
} else {
|
||||
switch (width) {
|
||||
case 1: return ("%" PRIu8);
|
||||
case 2: return ("%" PRIu16);
|
||||
case 4: return ("%" PRIu32);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BHND_NVRAM_SFMT_LEDDC:
|
||||
switch (width) {
|
||||
case 1: return ("%02" PRIx8);
|
||||
case 2: return ("%04" PRIx16);
|
||||
case 4: return ("%08" PRIx32);
|
||||
}
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_SFMT_CCODE:
|
||||
switch (width) {
|
||||
case 1: return ("%c");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and return the variable definition for @p varname, if any.
|
||||
*
|
||||
* @param varname variable name
|
||||
*
|
||||
* @retval bhnd_nvram_vardefn If a valid definition for @p varname is found.
|
||||
* @retval NULL If no definition for @p varname is found.
|
||||
*/
|
||||
const struct bhnd_nvram_vardefn *
|
||||
bhnd_nvram_find_vardefn(const char *varname)
|
||||
{
|
||||
size_t min, mid, max;
|
||||
int order;
|
||||
|
||||
/*
|
||||
* Locate the requested variable using a binary search.
|
||||
*
|
||||
* The variable table is guaranteed to be sorted in lexicographical
|
||||
* order (using the 'C' locale for collation rules)
|
||||
*/
|
||||
min = 0;
|
||||
mid = 0;
|
||||
max = nitems(bhnd_nvram_vardefs) - 1;
|
||||
|
||||
while (max >= min) {
|
||||
/* Select midpoint */
|
||||
mid = (min + max) / 2;
|
||||
|
||||
/* Determine which side of the partition to search */
|
||||
order = strcmp(bhnd_nvram_vardefs[mid].name, varname);
|
||||
if (order < 0) {
|
||||
/* Search upper partition */
|
||||
min = mid + 1;
|
||||
} else if (order > 0) {
|
||||
/* Search lower partition */
|
||||
max = mid - 1;
|
||||
} else if (order == 0) {
|
||||
/* Match found */
|
||||
return (&bhnd_nvram_vardefs[mid]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an NVRAM variable name.
|
||||
*
|
||||
* Scans for special characters (path delimiters, value delimiters, path
|
||||
* alias prefixes), returning false if the given name cannot be used
|
||||
* as a relative NVRAM key.
|
||||
*
|
||||
* @param name A relative NVRAM variable name to validate.
|
||||
* @param name_len The length of @p name, in bytes.
|
||||
*
|
||||
* @retval true If @p name is a valid relative NVRAM key.
|
||||
* @retval false If @p name should not be used as a relative NVRAM key.
|
||||
*/
|
||||
bool
|
||||
bhnd_nvram_validate_name(const char *name, size_t name_len)
|
||||
{
|
||||
size_t limit;
|
||||
|
||||
limit = strnlen(name, name_len);
|
||||
if (limit == 0)
|
||||
return (false);
|
||||
|
||||
/* Disallow path alias prefixes ([0-9]+:.*) */
|
||||
if (limit >= 2 && isdigit(*name)) {
|
||||
for (const char *p = name; p - name < limit; p++) {
|
||||
if (isdigit(*p))
|
||||
continue;
|
||||
else if (*p == ':')
|
||||
return (false);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan for special characters */
|
||||
for (const char *p = name; p - name < limit; p++) {
|
||||
switch (*p) {
|
||||
case '/': /* path delimiter */
|
||||
case '=': /* key=value delimiter */
|
||||
return (false);
|
||||
|
||||
default:
|
||||
if (isspace(*p) || !isascii(*p))
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an octet string, such as a MAC address, consisting of hex octets
|
||||
* separated with ':' or '-'.
|
||||
*
|
||||
* @param value The octet string to parse.
|
||||
* @param value_len The length of @p value, in bytes.
|
||||
* @param buf The output buffer to which parsed octets will be written. May be
|
||||
* NULL.
|
||||
* @param[in,out] len The capacity of @p buf. On success, will be set
|
||||
* to the actual size of the requested value.
|
||||
* @param type
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_parse_octet_string(const char *value, size_t value_len, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
size_t limit, nbytes, width;
|
||||
size_t slen;
|
||||
uint8_t octet;
|
||||
char delim;
|
||||
|
||||
slen = strnlen(value, value_len);
|
||||
|
||||
nbytes = 0;
|
||||
if (buf != NULL)
|
||||
limit = *len;
|
||||
else
|
||||
limit = 0;
|
||||
|
||||
/* Type must have a fixed width */
|
||||
if ((width = bhnd_nvram_type_width(type)) == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* String length (not including NUL) must be aligned on an octet
|
||||
* boundary ('AA:BB', not 'AA:B', etc), and must be large enough
|
||||
* to contain at least two octet entries. */
|
||||
if (slen % 3 != 2 || slen < sizeof("AA:BB") - 1)
|
||||
return (EINVAL);
|
||||
|
||||
/* Identify the delimiter used. The standard delimiter for
|
||||
* MAC addresses is ':', but some earlier NVRAM formats may use
|
||||
* '-' */
|
||||
switch ((delim = value[2])) {
|
||||
case ':':
|
||||
case '-':
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Parse octets */
|
||||
for (const char *p = value; p - value < value_len; p++) {
|
||||
void *outp;
|
||||
size_t pos;
|
||||
unsigned char c;
|
||||
|
||||
pos = (p - value);
|
||||
|
||||
/* Skip delimiter after each octet */
|
||||
if (pos % 3 == 2) {
|
||||
if (*p == delim)
|
||||
continue;
|
||||
|
||||
if (*p == '\0')
|
||||
return (0);
|
||||
|
||||
/* No delimiter? */
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
c = *(const unsigned char *)p;
|
||||
|
||||
if (isdigit(c))
|
||||
c -= '0';
|
||||
else if (isxdigit(c))
|
||||
c -= islower(c) ? 'a' - 10 : 'A' - 10;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (pos % 3 == 0) {
|
||||
/* MSB */
|
||||
octet = (c << 4);
|
||||
continue;
|
||||
} else if (pos % 3 == 1) {
|
||||
/* LSB */
|
||||
octet |= (c & 0xF);
|
||||
}
|
||||
|
||||
/* Skip writing? */
|
||||
if (limit < width || limit - width < nbytes) {
|
||||
nbytes += width;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Write output */
|
||||
outp = ((uint8_t *)buf) + nbytes;
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
*(uint8_t *)outp = octet;
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
*(uint16_t *)outp = octet;
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
*(uint32_t *)outp = octet;
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
if (octet > INT8_MAX)
|
||||
return (ERANGE);
|
||||
*(int8_t *)outp = (int8_t)octet;
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
*(int16_t *)outp = (int8_t)octet;
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
*(int32_t *)outp = (int8_t)octet;
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
#if (CHAR_MAX < UINT8_MAX)
|
||||
if (octet > CHAR_MAX)
|
||||
return (ERANGE);
|
||||
#endif
|
||||
*(char *)outp = (char)octet;
|
||||
break;
|
||||
default:
|
||||
printf("unknown type %d\n", type);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
nbytes += width;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a new variable hash table with @p nelements.
|
||||
*
|
||||
* @param map Hash table instance to be initialized.
|
||||
* @param nelements The number of hash table buckets to allocate.
|
||||
* @param flags Hash table flags (HASH_*).
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_varmap_init(struct bhnd_nvram_varmap *map, size_t nelements,
|
||||
int flags)
|
||||
{
|
||||
map->table = hashinit_flags(nelements, M_BHND_NVRAM, &map->mask,
|
||||
flags);
|
||||
if (map->table == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocate all resources associated with @p map.
|
||||
*
|
||||
* @param map Hash table to be deallocated.
|
||||
*/
|
||||
void
|
||||
bhnd_nvram_varmap_free(struct bhnd_nvram_varmap *map)
|
||||
{
|
||||
struct bhnd_nvram_tuple *t, *tnext;
|
||||
|
||||
/* Free all elements */
|
||||
for (size_t i = 0; i <= map->mask; i++) {
|
||||
LIST_FOREACH_SAFE(t, &map->table[i], t_link, tnext) {
|
||||
LIST_REMOVE(t, t_link);
|
||||
bhnd_nvram_tuple_free(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free hash table */
|
||||
hashdestroy(map->table, M_BHND_NVRAM, map->mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a variable entry to @p map.
|
||||
*
|
||||
* @param map Hash table to modify.
|
||||
* @param name Variable name.
|
||||
* @param value Variable value.
|
||||
* @param value_len The length of @p value, in bytes.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOMEM unable to allocate new entry
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_varmap_add(struct bhnd_nvram_varmap *map, const char *name,
|
||||
const char *value, size_t value_len)
|
||||
{
|
||||
struct bhnd_nvram_tuples *head;
|
||||
struct bhnd_nvram_tuple *t;
|
||||
|
||||
/* Locate target bucket */
|
||||
head = &map->table[hash32_str(name, HASHINIT) & map->mask];
|
||||
|
||||
/* Allocate new entry */
|
||||
if ((t = bhnd_nvram_tuple_alloc(name, value)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Remove any existing entry */
|
||||
bhnd_nvram_varmap_remove(map, name);
|
||||
|
||||
/* Insert new entry */
|
||||
LIST_INSERT_HEAD(head, t, t_link);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove @p map in @p tuples, if it exists.
|
||||
*
|
||||
* @param map Hash table to modify.
|
||||
* @param key Key to remove.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOENT If @p name is not found in @p map.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_varmap_remove(struct bhnd_nvram_varmap *map, const char *name)
|
||||
{
|
||||
struct bhnd_nvram_tuples *head;
|
||||
struct bhnd_nvram_tuple *t;
|
||||
size_t name_len;
|
||||
|
||||
/* Locate target bucket */
|
||||
head = &map->table[hash32_str(name, HASHINIT) & map->mask];
|
||||
name_len = strlen(name);
|
||||
|
||||
LIST_FOREACH(t, head, t_link) {
|
||||
if (t->name_len != name_len)
|
||||
continue;
|
||||
|
||||
if (strncmp(t->name, name, name_len) != 0)
|
||||
continue;
|
||||
|
||||
LIST_REMOVE(t, t_link);
|
||||
bhnd_nvram_tuple_free(t);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for @p name in @p map.
|
||||
*
|
||||
* @param map Hash table to modify.
|
||||
* @param name Variable name.
|
||||
* @param name_len Length of @p name, not including trailing NUL.
|
||||
*
|
||||
* @retval bhnd_nvram_tuple If @p name is found in @p map.
|
||||
* @retval NULL If @p name is not found.
|
||||
*/
|
||||
struct bhnd_nvram_tuple *
|
||||
bhnd_nvram_varmap_find(struct bhnd_nvram_varmap *map, const char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
struct bhnd_nvram_tuples *head;
|
||||
struct bhnd_nvram_tuple *t;
|
||||
|
||||
head = &map->table[hash32_str(name, HASHINIT) & map->mask];
|
||||
|
||||
LIST_FOREACH(t, head, t_link) {
|
||||
if (t->name_len != name_len)
|
||||
continue;
|
||||
|
||||
if (strncmp(t->name, name, name_len) != 0)
|
||||
continue;
|
||||
|
||||
/* Match */
|
||||
return (t);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for @p name in @p map.
|
||||
*
|
||||
* @param map Hash table to modify.
|
||||
* @param name Variable name.
|
||||
* @param name_len Length of @p name, not including trailing NUL.
|
||||
*
|
||||
* @retval true If @p name is found in @p tuples.
|
||||
* @retval false If @p name is not found.
|
||||
*/
|
||||
bool bhnd_nvram_varmap_contains(struct bhnd_nvram_varmap *map,
|
||||
const char *name, size_t name_len)
|
||||
{
|
||||
return (bhnd_nvram_varmap_find(map, name, name_len) != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new tuple with @p name and @p value.
|
||||
*
|
||||
* @param name Variable name.
|
||||
* @param value Variable value.
|
||||
*
|
||||
* @retval bhnd_nvram_tuple success.
|
||||
* @retval NULL if allocation fails.
|
||||
*/
|
||||
struct bhnd_nvram_tuple *
|
||||
bhnd_nvram_tuple_alloc(const char *name, const char *value)
|
||||
{
|
||||
struct bhnd_nvram_tuple *t;
|
||||
|
||||
t = malloc(sizeof(*t), M_BHND_NVRAM, M_NOWAIT);
|
||||
if (t == NULL)
|
||||
return (NULL);
|
||||
|
||||
t->name_len = strlen(name);
|
||||
t->name = malloc(t->name_len+1, M_BHND_NVRAM, M_NOWAIT);
|
||||
|
||||
t->value_len = strlen(value);
|
||||
t->value = malloc(t->value_len+1, M_BHND_NVRAM, M_NOWAIT);
|
||||
|
||||
if (t->name == NULL || t->value == NULL)
|
||||
goto failed;
|
||||
|
||||
strcpy(t->name, name);
|
||||
strcpy(t->value, value);
|
||||
|
||||
return (t);
|
||||
|
||||
failed:
|
||||
if (t->name != NULL)
|
||||
free(t->name, M_BHND_NVRAM);
|
||||
|
||||
if (t->value != NULL)
|
||||
free(t->value, M_BHND_NVRAM);
|
||||
|
||||
free(t, M_BHND_NVRAM);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
bhnd_nvram_tuple_free(struct bhnd_nvram_tuple *tuple)
|
||||
{
|
||||
free(tuple->name, M_BHND_NVRAM);
|
||||
free(tuple->value, M_BHND_NVRAM);
|
||||
free(tuple, M_BHND_NVRAM);
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_COMMON_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_COMMON_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include "bhnd_nvram.h"
|
||||
|
||||
struct bhnd_nvram_tuple;
|
||||
struct bhnd_nvram_varmap;
|
||||
|
||||
struct bhnd_nvram_vardefn;
|
||||
|
||||
MALLOC_DECLARE(M_BHND_NVRAM);
|
||||
|
||||
extern const uint8_t bhnd_nvram_crc8_tab[];
|
||||
|
||||
#define BHND_NVRAM_CRC8_INITIAL 0xFF /**< Initial bhnd_nvram_crc8 value */
|
||||
#define BHND_NVRAM_CRC8_VALID 0x9F /**< Valid CRC-8 checksum */
|
||||
#define BHND_SPROMREV_MAX UINT8_MAX /**< maximum supported SPROM revision */
|
||||
|
||||
|
||||
/** NVRAM data type string representations */
|
||||
typedef enum {
|
||||
BHND_NVRAM_SFMT_HEX = 1, /**< hex format */
|
||||
BHND_NVRAM_SFMT_DEC = 2, /**< decimal format */
|
||||
BHND_NVRAM_SFMT_MACADDR = 3, /**< mac address (canonical form, hex octets,
|
||||
separated with ':') */
|
||||
BHND_NVRAM_SFMT_LEDDC = 4, /**< LED PWM duty-cycle (2 bytes -- on/off) */
|
||||
BHND_NVRAM_SFMT_CCODE = 5 /**< count code format (2-3 ASCII chars, or hex string) */
|
||||
} bhnd_nvram_sfmt;
|
||||
|
||||
size_t bhnd_nvram_type_width(bhnd_nvram_type type);
|
||||
const char *bhnd_nvram_type_fmt(bhnd_nvram_type type,
|
||||
bhnd_nvram_sfmt sfmt, size_t elem_num);
|
||||
|
||||
const struct bhnd_nvram_vardefn *bhnd_nvram_find_vardefn(const char *varname);
|
||||
|
||||
bool bhnd_nvram_validate_name(const char *name,
|
||||
size_t name_len);
|
||||
int bhnd_nvram_parse_octet_string(
|
||||
const char *value, size_t value_len,
|
||||
void *buf, size_t *len,
|
||||
bhnd_nvram_type type);
|
||||
|
||||
int bhnd_nvram_varmap_init(
|
||||
struct bhnd_nvram_varmap *map,
|
||||
size_t nelements, int flags);
|
||||
void bhnd_nvram_varmap_free(
|
||||
struct bhnd_nvram_varmap *map);
|
||||
int bhnd_nvram_varmap_add(
|
||||
struct bhnd_nvram_varmap *map,
|
||||
const char *name, const char *value,
|
||||
size_t value_len);
|
||||
int bhnd_nvram_varmap_remove(
|
||||
struct bhnd_nvram_varmap *map,
|
||||
const char *name);
|
||||
struct bhnd_nvram_tuple *bhnd_nvram_varmap_find(
|
||||
struct bhnd_nvram_varmap *map,
|
||||
const char *name, size_t name_len);
|
||||
bool bhnd_nvram_varmap_contains(
|
||||
struct bhnd_nvram_varmap *map,
|
||||
const char *name, size_t name_len);
|
||||
|
||||
struct bhnd_nvram_tuple *bhnd_nvram_tuple_alloc(const char *name,
|
||||
const char *value);
|
||||
void bhnd_nvram_tuple_free(
|
||||
struct bhnd_nvram_tuple *tuple);
|
||||
|
||||
/** NVRAM variable flags */
|
||||
enum {
|
||||
BHND_NVRAM_VF_ARRAY = (1<<0), /**< variable is an array */
|
||||
BHND_NVRAM_VF_MFGINT = (1<<1), /**< mfg-internal variable; should not be externally visible */
|
||||
BHND_NVRAM_VF_IGNALL1 = (1<<2) /**< hide variable if its value has all bits set. */
|
||||
};
|
||||
|
||||
/** SPROM revision compatibility declaration */
|
||||
struct bhnd_sprom_compat {
|
||||
uint8_t first; /**< first compatible SPROM revision */
|
||||
uint8_t last; /**< last compatible SPROM revision, or BHND_SPROMREV_MAX */
|
||||
};
|
||||
|
||||
/** SPROM value descriptor */
|
||||
struct bhnd_sprom_offset {
|
||||
uint16_t offset; /**< byte offset within SPROM */
|
||||
bool cont:1; /**< value should be bitwise OR'd with the
|
||||
* previous offset descriptor */
|
||||
bhnd_nvram_type type:7; /**< data type */
|
||||
int8_t shift; /**< shift to be applied to the value */
|
||||
uint32_t mask; /**< mask to be applied to the value(s) */
|
||||
};
|
||||
|
||||
/** SPROM-specific variable definition */
|
||||
struct bhnd_sprom_vardefn {
|
||||
struct bhnd_sprom_compat compat; /**< sprom compatibility declaration */
|
||||
const struct bhnd_sprom_offset *offsets; /**< offset descriptors */
|
||||
size_t num_offsets; /**< number of offset descriptors */
|
||||
};
|
||||
|
||||
/** NVRAM variable definition */
|
||||
struct bhnd_nvram_vardefn {
|
||||
const char *name; /**< variable name */
|
||||
bhnd_nvram_type type; /**< base data type */
|
||||
bhnd_nvram_sfmt sfmt; /**< string format */
|
||||
uint32_t flags; /**< BHND_NVRAM_VF_* flags */
|
||||
|
||||
const struct bhnd_sprom_vardefn *sp_defs; /**< SPROM-specific variable definitions */
|
||||
size_t num_sp_defs; /**< number of sprom definitions */
|
||||
};
|
||||
|
||||
/**
|
||||
* NVRAM value tuple.
|
||||
*/
|
||||
struct bhnd_nvram_tuple {
|
||||
char *name; /**< variable name. */
|
||||
size_t name_len; /**< variable length. */
|
||||
char *value; /**< value, or NULL if this tuple represents variable
|
||||
deletion */
|
||||
size_t value_len; /**< value length. */
|
||||
|
||||
LIST_ENTRY(bhnd_nvram_tuple) t_link;
|
||||
};
|
||||
|
||||
LIST_HEAD(bhnd_nvram_tuples, bhnd_nvram_tuple);
|
||||
|
||||
/** NVRAM tuple hash table */
|
||||
struct bhnd_nvram_varmap {
|
||||
struct bhnd_nvram_tuples *table; /**< hash buckets */
|
||||
u_long mask; /**< hash index mask */
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate CRC-8 over @p buf.
|
||||
*
|
||||
* @param buf input buffer
|
||||
* @param size buffer size
|
||||
* @param crc last computed crc, or BHND_NVRAM_CRC8_INITIAL
|
||||
*/
|
||||
static inline uint8_t
|
||||
bhnd_nvram_crc8(const void *buf, size_t size, uint8_t crc)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)buf;
|
||||
while (size--)
|
||||
crc = bhnd_nvram_crc8_tab[(crc ^ *p++)];
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_COMMON_H_ */
|
527
sys/dev/bhnd/nvram/bhnd_nvram_data.c
Normal file
527
sys/dev/bhnd/nvram/bhnd_nvram_data.c
Normal file
@ -0,0 +1,527 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/_inttypes.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
#include "bhnd_nvram_data.h"
|
||||
|
||||
/**
|
||||
* Return a human-readable description for the given NVRAM data class.
|
||||
*
|
||||
* @param cls The NVRAM class.
|
||||
*/
|
||||
const char *
|
||||
bhnd_nvram_data_class_desc(bhnd_nvram_data_class_t *cls)
|
||||
{
|
||||
return (cls->desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe to see if this NVRAM data class class supports the data mapped by the
|
||||
* given I/O context, returning a BHND_NVRAM_DATA_PROBE probe result.
|
||||
*
|
||||
* @param cls The NVRAM class.
|
||||
* @param io An I/O context mapping the NVRAM data.
|
||||
*
|
||||
* @retval 0 if this is the only possible NVRAM data class for @p io.
|
||||
* @retval negative if the probe succeeds, a negative value should be returned;
|
||||
* the class returning the highest negative value should be selected to handle
|
||||
* NVRAM parsing.
|
||||
* @retval ENXIO If the NVRAM format is not handled by @p cls.
|
||||
* @retval positive if an error occurs during probing, a regular unix error
|
||||
* code should be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_probe(bhnd_nvram_data_class_t *cls, struct bhnd_nvram_io *io)
|
||||
{
|
||||
return (cls->op_probe(io));
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe to see if an NVRAM data class in @p classes supports parsing
|
||||
* of the data mapped by @p io, returning the parsed data in @p data.
|
||||
*
|
||||
* The caller is responsible for deallocating the returned instance via
|
||||
* bhnd_nvram_data_release().
|
||||
*
|
||||
* @param[out] data On success, the parsed NVRAM data instance.
|
||||
* @param io An I/O context mapping the NVRAM data to be copied and parsed.
|
||||
* @param classes An array of NVRAM data classes to be probed, or NULL to
|
||||
* probe the default supported set.
|
||||
* @param num_classes The number of NVRAM data classes in @p classes.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENXIO if no class is found capable of parsing @p io.
|
||||
* @retval non-zero if an error otherwise occurs during allocation,
|
||||
* initialization, or parsing of the NVRAM data, a regular unix error code
|
||||
* will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_probe_classes(struct bhnd_nvram_data **data,
|
||||
struct bhnd_nvram_io *io, bhnd_nvram_data_class_t *classes[],
|
||||
size_t num_classes)
|
||||
{
|
||||
bhnd_nvram_data_class_t *cls;
|
||||
int error, prio, result;
|
||||
|
||||
cls = NULL;
|
||||
prio = 0;
|
||||
*data = NULL;
|
||||
|
||||
/* If class array is NULL, default to our linker set */
|
||||
if (classes == NULL) {
|
||||
classes = SET_BEGIN(bhnd_nvram_data_class_set);
|
||||
num_classes = SET_COUNT(bhnd_nvram_data_class_set);
|
||||
}
|
||||
|
||||
/* Try to find the best data class capable of parsing io */
|
||||
for (size_t i = 0; i < num_classes; i++) {
|
||||
bhnd_nvram_data_class_t *next_cls;
|
||||
|
||||
next_cls = classes[i];
|
||||
|
||||
/* Try to probe */
|
||||
result = bhnd_nvram_data_probe(next_cls, io);
|
||||
|
||||
/* The parser did not match if an error was returned */
|
||||
if (result > 0)
|
||||
continue;
|
||||
|
||||
/* Lower priority than previous match; keep
|
||||
* searching */
|
||||
if (cls != NULL && result <= prio)
|
||||
continue;
|
||||
|
||||
/* Drop any previously parsed data */
|
||||
if (*data != NULL) {
|
||||
bhnd_nvram_data_release(*data);
|
||||
*data = NULL;
|
||||
}
|
||||
|
||||
/* If this is a 'maybe' match, attempt actual parsing to
|
||||
* verify that this does in fact match */
|
||||
if (result <= BHND_NVRAM_DATA_PROBE_MAYBE) {
|
||||
/* If parsing fails, keep searching */
|
||||
error = bhnd_nvram_data_new(next_cls, data, io);
|
||||
if (error)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Record best new match */
|
||||
prio = result;
|
||||
cls = next_cls;
|
||||
|
||||
|
||||
/* Terminate search immediately on
|
||||
* BHND_NVRAM_DATA_PROBE_SPECIFIC */
|
||||
if (result == BHND_NVRAM_DATA_PROBE_SPECIFIC)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no match, return error */
|
||||
if (cls == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
/* If the NVRAM data was not parsed above, do so now */
|
||||
if (*data == NULL) {
|
||||
if ((error = bhnd_nvram_data_new(cls, data, io)))
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new instance of data class @p cls, copying and
|
||||
* parsing NVRAM data from @p io.
|
||||
*
|
||||
* The caller is responsible for releasing the returned parser instance
|
||||
* reference via bhnd_nvram_data_release().
|
||||
*
|
||||
* @param cls If non-NULL, the data class to be allocated. If NULL,
|
||||
* bhnd_nvram_data_probe_classes() will be used to determine the data format.
|
||||
* @param[out] nv On success, a pointer to the newly allocated NVRAM data instance.
|
||||
* @param io An I/O context mapping the NVRAM data to be copied and parsed.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero if an error occurs during allocation or initialization, a
|
||||
* regular unix error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_new(bhnd_nvram_data_class_t *cls,
|
||||
struct bhnd_nvram_data **nv, struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_data *data;
|
||||
int error;
|
||||
|
||||
/* If NULL, try to identify the appropriate class */
|
||||
if (cls == NULL)
|
||||
return (bhnd_nvram_data_probe_classes(nv, io, NULL, 0));
|
||||
|
||||
/* Allocate new instance */
|
||||
BHND_NV_ASSERT(sizeof(struct bhnd_nvram_data) <= cls->size,
|
||||
("instance size %zu less than minimum %zu", cls->size,
|
||||
sizeof(struct bhnd_nvram_data)));
|
||||
|
||||
data = bhnd_nv_calloc(1, cls->size);
|
||||
data->cls = cls;
|
||||
refcount_init(&data->refs, 1);
|
||||
|
||||
/* Let the class handle initialization */
|
||||
if ((error = cls->op_new(data, io))) {
|
||||
bhnd_nv_free(data);
|
||||
return (error);
|
||||
}
|
||||
|
||||
*nv = data;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retain and return a reference to the given data instance.
|
||||
*
|
||||
* @param nv The reference to be retained.
|
||||
*/
|
||||
struct bhnd_nvram_data *
|
||||
bhnd_nvram_data_retain(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
refcount_acquire(&nv->refs);
|
||||
return (nv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a reference to the given data instance.
|
||||
*
|
||||
* If this is the last reference, the data instance and its associated
|
||||
* resources will be freed.
|
||||
*
|
||||
* @param nv The reference to be released.
|
||||
*/
|
||||
void
|
||||
bhnd_nvram_data_release(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
if (!refcount_release(&nv->refs))
|
||||
return;
|
||||
|
||||
/* Free any internal resources */
|
||||
nv->cls->op_free(nv);
|
||||
|
||||
/* Free the instance allocation */
|
||||
bhnd_nv_free(nv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to @p nv's data class.
|
||||
*
|
||||
* @param nv The NVRAM data instance to be queried.
|
||||
*/
|
||||
bhnd_nvram_data_class_t *
|
||||
bhnd_nvram_data_class(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (nv->cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of variables in @p nv.
|
||||
*
|
||||
* @param nv The NVRAM data to be queried.
|
||||
*/
|
||||
size_t
|
||||
bhnd_nvram_data_count(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (nv->cls->op_count(nv));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the size of the serialized form of @p nv.
|
||||
*
|
||||
* Serialization may be performed via bhnd_nvram_data_serialize().
|
||||
*
|
||||
* @param nv The NVRAM data to be queried.
|
||||
* @param[out] len On success, will be set to the computed size.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero if computing the serialized size otherwise fails, a
|
||||
* regular unix error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_size(struct bhnd_nvram_data *nv, size_t *len)
|
||||
{
|
||||
return (nv->cls->op_size(nv, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the NVRAM data to @p buf, using the NVRAM data class' native
|
||||
* format.
|
||||
*
|
||||
* The resulting serialization may be reparsed with @p nv's BHND NVRAM data
|
||||
* class.
|
||||
*
|
||||
* @param nv The NVRAM data to be serialized.
|
||||
* @param[out] buf On success, the serialed NVRAM data 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 length of the serialized data.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
|
||||
* small to hold the serialized data.
|
||||
* @retval non-zero If serialization otherwise fails, a regular unix error
|
||||
* code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_serialize(struct bhnd_nvram_data *nv,
|
||||
void *buf, size_t *len)
|
||||
{
|
||||
return (nv->cls->op_serialize(nv, buf, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the capability flags (@see BHND_NVRAM_DATA_CAP_*) for @p nv.
|
||||
*
|
||||
* @param nv The NVRAM data to be queried.
|
||||
*/
|
||||
uint32_t
|
||||
bhnd_nvram_data_caps(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (nv->cls->op_caps(nv));
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over @p nv, returning the names of subsequent variables.
|
||||
*
|
||||
* @param nv The NVRAM data to be iterated.
|
||||
* @param[in,out] cookiep A pointer to a cookiep value previously returned
|
||||
* by bhnd_nvram_data_next(), or a NULL value to
|
||||
* begin iteration.
|
||||
*
|
||||
* @return Returns the next variable name, or NULL if there are no more
|
||||
* variables defined in @p nv.
|
||||
*/
|
||||
const char *
|
||||
bhnd_nvram_data_next(struct bhnd_nvram_data *nv, void **cookiep)
|
||||
{
|
||||
return (nv->cls->op_next(nv, cookiep));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search @p nv for a named variable, returning the variable's opaque reference
|
||||
* if found, or NULL if unavailable.
|
||||
*
|
||||
* The BHND_NVRAM_DATA_CAP_INDEXED capability flag will be returned by
|
||||
* bhnd_nvram_data_caps() if @p nv supports effecient name-based
|
||||
* lookups.
|
||||
*
|
||||
* @param nv The NVRAM data to search.
|
||||
* @param name The name to search for.
|
||||
*
|
||||
* @retval non-NULL If @p name is found, the opaque cookie value will be
|
||||
* returned.
|
||||
* @retval NULL If @p name is not found.
|
||||
*/
|
||||
void *
|
||||
bhnd_nvram_data_find(struct bhnd_nvram_data *nv, const char *name)
|
||||
{
|
||||
return (nv->cls->op_find(nv, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic implementation of bhnd_nvram_data_find().
|
||||
*
|
||||
* This implementation will use bhnd_nvram_data_next() to perform a
|
||||
* simple O(n) case-insensitve search for @p name.
|
||||
*/
|
||||
void *
|
||||
bhnd_nvram_data_generic_find(struct bhnd_nvram_data *nv, const char *name)
|
||||
{
|
||||
const char *next;
|
||||
void *cookiep;
|
||||
|
||||
cookiep = NULL;
|
||||
while ((next = bhnd_nvram_data_next(nv, &cookiep))) {
|
||||
if (strcasecmp(name, next) == 0)
|
||||
return (cookiep);
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a variable and decode as @p type.
|
||||
*
|
||||
* @param nv The NVRAM data.
|
||||
* @param cookiep An NVRAM variable cookie previously returned
|
||||
* via bhnd_nvram_data_next() or
|
||||
* bhnd_nvram_data_find().
|
||||
* @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 EFTYPE If the variable data cannot be coerced to @p type.
|
||||
* @retval ERANGE If value coercion would overflow @p type.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
return (nv->cls->op_getvar(nv, cookiep, buf, len, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic implementation of bhnd_nvram_data_getvar().
|
||||
*
|
||||
* This implementation will call bhnd_nvram_data_getvar_ptr() to fetch
|
||||
* a pointer to the variable data and perform data coercion on behalf
|
||||
* of the caller.
|
||||
*
|
||||
* If a variable definition for the requested variable is available via
|
||||
* bhnd_nvram_find_vardefn(), the definition will be used to provide
|
||||
* formatting hints to bhnd_nvram_coerce_value().
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_data_generic_rp_getvar(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
void *outp, size_t *olen, bhnd_nvram_type otype)
|
||||
{
|
||||
bhnd_nvram_val_t val;
|
||||
const struct bhnd_nvram_vardefn *vdefn;
|
||||
const bhnd_nvram_val_fmt_t *fmt;
|
||||
const char *name;
|
||||
const void *vptr;
|
||||
bhnd_nvram_type vtype;
|
||||
size_t vlen;
|
||||
int error;
|
||||
|
||||
BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR,
|
||||
("instance does not advertise READ_PTR support"));
|
||||
|
||||
/* Fetch pointer to our variable data */
|
||||
vptr = bhnd_nvram_data_getvar_ptr(nv, cookiep, &vlen, &vtype);
|
||||
if (vptr == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/* Use the NVRAM string support */
|
||||
switch (vtype) {
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY:
|
||||
fmt = &bhnd_nvram_val_bcm_string_fmt;
|
||||
break;
|
||||
default:
|
||||
fmt = NULL;
|
||||
}
|
||||
|
||||
/* Check the variable definition table for a matching entry; if
|
||||
* it exists, use it to populate the value format. */
|
||||
name = bhnd_nvram_data_getvar_name(nv, cookiep);
|
||||
vdefn = bhnd_nvram_find_vardefn(name);
|
||||
if (vdefn != NULL)
|
||||
fmt = vdefn->fmt;
|
||||
|
||||
/* Attempt value coercion */
|
||||
error = bhnd_nvram_val_init(&val, fmt, vptr, vlen, vtype,
|
||||
BHND_NVRAM_VAL_BORROW_DATA);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = bhnd_nvram_val_encode(&val, outp, olen, otype);
|
||||
|
||||
/* Clean up */
|
||||
bhnd_nvram_val_release(&val);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* If available and supported by the NVRAM data instance, return a reference
|
||||
* to the internal buffer containing an entry's variable data,
|
||||
*
|
||||
* Note that string values may not be NUL terminated.
|
||||
*
|
||||
* @param nv The NVRAM data.
|
||||
* @param cookiep An NVRAM variable cookie previously returned
|
||||
* via bhnd_nvram_data_next() or
|
||||
* bhnd_nvram_data_find().
|
||||
* @param[out] len On success, will be set to the actual size of
|
||||
* the requested value.
|
||||
* @param[out] type The data type of the entry data.
|
||||
*
|
||||
* @retval non-NULL success
|
||||
* @retval NULL if direct data access is unsupported by @p nv, or
|
||||
* unavailable for @p cookiep.
|
||||
*/
|
||||
const void *
|
||||
bhnd_nvram_data_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
size_t *len, bhnd_nvram_type *type)
|
||||
{
|
||||
return (nv->cls->op_getvar_ptr(nv, cookiep, len, type));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the variable name associated with a given @p cookiep.
|
||||
* @param nv The NVRAM data to be iterated.
|
||||
* @param[in,out] cookiep A pointer to a cookiep value previously returned
|
||||
* via bhnd_nvram_data_next() or
|
||||
* bhnd_nvram_data_find().
|
||||
*
|
||||
* @return Returns the variable's name.
|
||||
*/
|
||||
const char *
|
||||
bhnd_nvram_data_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
|
||||
{
|
||||
return (nv->cls->op_getvar_name(nv, cookiep));
|
||||
}
|
137
sys/dev/bhnd/nvram/bhnd_nvram_data.h
Normal file
137
sys/dev/bhnd/nvram/bhnd_nvram_data.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_DATA_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_DATA_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram.h"
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
/* NVRAM data class */
|
||||
typedef struct bhnd_nvram_data_class bhnd_nvram_data_class_t;
|
||||
|
||||
/* NVRAM data instance */
|
||||
struct bhnd_nvram_data;
|
||||
|
||||
/** Declare a bhnd_nvram_data_class with name @p _n */
|
||||
#define BHND_NVRAM_DATA_CLASS_DECL(_n) \
|
||||
extern struct bhnd_nvram_data_class bhnd_nvram_ ## _n ## _class
|
||||
|
||||
BHND_NVRAM_DATA_CLASS_DECL(bcm);
|
||||
BHND_NVRAM_DATA_CLASS_DECL(bcmraw);
|
||||
BHND_NVRAM_DATA_CLASS_DECL(tlv);
|
||||
BHND_NVRAM_DATA_CLASS_DECL(btxt);
|
||||
BHND_NVRAM_DATA_CLASS_DECL(sprom);
|
||||
|
||||
/** bhnd_nvram_data capabilities */
|
||||
enum {
|
||||
/** Supports efficient lookup of variables by name */
|
||||
BHND_NVRAM_DATA_CAP_INDEXED = (1<<0),
|
||||
|
||||
/** Supports direct access to backing buffer */
|
||||
BHND_NVRAM_DATA_CAP_READ_PTR = (1<<1),
|
||||
|
||||
/** Supports device path prefixed variables */
|
||||
BHND_NVRAM_DATA_CAP_DEVPATHS = (1<<2),
|
||||
};
|
||||
|
||||
/**
|
||||
* A standard set of probe priorities returned by bhnd_nvram_data_probe().
|
||||
*
|
||||
* Priority is defined in ascending order, with 0 being the highest priority.
|
||||
* Return values greater than zero are interpreted as regular unix error codes.
|
||||
*/
|
||||
enum {
|
||||
BHND_NVRAM_DATA_PROBE_MAYBE = -40, /**< Possible match */
|
||||
BHND_NVRAM_DATA_PROBE_DEFAULT = -20, /**< Definite match of a base
|
||||
OS-supplied data class */
|
||||
BHND_NVRAM_DATA_PROBE_SPECIFIC = 0, /**< Terminate search and use
|
||||
this data class for
|
||||
parsing */
|
||||
};
|
||||
|
||||
const char *bhnd_nvram_data_class_desc(
|
||||
bhnd_nvram_data_class_t *cls);
|
||||
|
||||
int bhnd_nvram_data_probe(bhnd_nvram_data_class_t *cls,
|
||||
struct bhnd_nvram_io *io);
|
||||
int bhnd_nvram_data_probe_classes(
|
||||
struct bhnd_nvram_data **data,
|
||||
struct bhnd_nvram_io *io,
|
||||
bhnd_nvram_data_class_t *classes[],
|
||||
size_t num_classes);
|
||||
|
||||
int bhnd_nvram_data_new(bhnd_nvram_data_class_t *cls,
|
||||
struct bhnd_nvram_data **nv,
|
||||
struct bhnd_nvram_io *io);
|
||||
|
||||
struct bhnd_nvram_data *bhnd_nvram_data_retain(struct bhnd_nvram_data *nv);
|
||||
void bhnd_nvram_data_release(struct bhnd_nvram_data *nv);
|
||||
|
||||
bhnd_nvram_data_class_t *bhnd_nvram_data_class(struct bhnd_nvram_data *nv);
|
||||
|
||||
size_t bhnd_nvram_data_count(struct bhnd_nvram_data *nv);
|
||||
|
||||
int bhnd_nvram_data_size(struct bhnd_nvram_data *nv,
|
||||
size_t *size);
|
||||
|
||||
int bhnd_nvram_data_serialize(struct bhnd_nvram_data *nv,
|
||||
void *buf, size_t *len);
|
||||
|
||||
uint32_t bhnd_nvram_data_caps(struct bhnd_nvram_data *nv);
|
||||
|
||||
const char *bhnd_nvram_data_next(struct bhnd_nvram_data *nv,
|
||||
void **cookiep);
|
||||
|
||||
void *bhnd_nvram_data_find(struct bhnd_nvram_data *nv,
|
||||
const char *name);
|
||||
|
||||
int bhnd_nvram_data_getvar(struct bhnd_nvram_data *nv,
|
||||
void *cookiep, void *buf, size_t *len,
|
||||
bhnd_nvram_type type);
|
||||
|
||||
const void *bhnd_nvram_data_getvar_ptr(struct bhnd_nvram_data *nv,
|
||||
void *cookiep, size_t *len, bhnd_nvram_type *type);
|
||||
|
||||
const char *bhnd_nvram_data_getvar_name(struct bhnd_nvram_data *nv,
|
||||
void *cookiep);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_DATA_H_ */
|
748
sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
Normal file
748
sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
Normal file
@ -0,0 +1,748 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
|
||||
#include "bhnd_nvram_data_bcmreg.h"
|
||||
#include "bhnd_nvram_data_bcmvar.h"
|
||||
|
||||
/*
|
||||
* Broadcom NVRAM data class.
|
||||
*
|
||||
* The Broadcom NVRAM NUL-delimited ASCII format is used by most
|
||||
* Broadcom SoCs.
|
||||
*
|
||||
* The NVRAM data is encoded as a standard header, followed by series of
|
||||
* NUL-terminated 'key=value' strings; the end of the stream is denoted
|
||||
* by a single extra NUL character.
|
||||
*/
|
||||
|
||||
struct bhnd_nvram_bcm;
|
||||
|
||||
static struct bhnd_nvram_bcm_hvar *bhnd_nvram_bcm_gethdrvar(
|
||||
struct bhnd_nvram_bcm *bcm,
|
||||
const char *name);
|
||||
static struct bhnd_nvram_bcm_hvar *bhnd_nvram_bcm_to_hdrvar(
|
||||
struct bhnd_nvram_bcm *bcm,
|
||||
void *cookiep);
|
||||
static size_t bhnd_nvram_bcm_hdrvar_index(
|
||||
struct bhnd_nvram_bcm *bcm,
|
||||
struct bhnd_nvram_bcm_hvar *hvar);
|
||||
/*
|
||||
* Set of BCM NVRAM header values that are required to be mirrored in the
|
||||
* NVRAM data itself.
|
||||
*
|
||||
* If they're not included in the parsed NVRAM data, we need to vend the
|
||||
* header-parsed values with their appropriate keys, and add them in any
|
||||
* updates to the NVRAM data.
|
||||
*
|
||||
* If they're modified in NVRAM, we need to sync the changes with the
|
||||
* the NVRAM header values.
|
||||
*/
|
||||
static const struct bhnd_nvram_bcm_hvar bhnd_nvram_bcm_hvars[] = {
|
||||
{
|
||||
.name = BCM_NVRAM_CFG0_SDRAM_INIT_VAR,
|
||||
.type = BHND_NVRAM_TYPE_UINT16,
|
||||
.len = sizeof(uint16_t),
|
||||
.nelem = 1,
|
||||
},
|
||||
{
|
||||
.name = BCM_NVRAM_CFG1_SDRAM_CFG_VAR,
|
||||
.type = BHND_NVRAM_TYPE_UINT16,
|
||||
.len = sizeof(uint16_t),
|
||||
.nelem = 1,
|
||||
},
|
||||
{
|
||||
.name = BCM_NVRAM_CFG1_SDRAM_REFRESH_VAR,
|
||||
.type = BHND_NVRAM_TYPE_UINT16,
|
||||
.len = sizeof(uint16_t),
|
||||
.nelem = 1,
|
||||
},
|
||||
{
|
||||
.name = BCM_NVRAM_SDRAM_NCDL_VAR,
|
||||
.type = BHND_NVRAM_TYPE_UINT32,
|
||||
.len = sizeof(uint32_t),
|
||||
.nelem = 1,
|
||||
},
|
||||
};
|
||||
|
||||
/** BCM NVRAM data class instance */
|
||||
struct bhnd_nvram_bcm {
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
struct bhnd_nvram_io *data; /**< backing buffer */
|
||||
|
||||
/** BCM header values */
|
||||
struct bhnd_nvram_bcm_hvar hvars[nitems(bhnd_nvram_bcm_hvars)];
|
||||
|
||||
size_t count; /**< total variable count */
|
||||
};
|
||||
|
||||
BHND_NVRAM_DATA_CLASS_DEFN(bcm, "Broadcom", sizeof(struct bhnd_nvram_bcm))
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcm_probe(struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_bcmhdr hdr;
|
||||
int error;
|
||||
|
||||
if ((error = bhnd_nvram_io_read(io, 0x0, &hdr, sizeof(hdr))))
|
||||
return (error);
|
||||
|
||||
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
|
||||
return (ENXIO);
|
||||
|
||||
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize @p bcm with the provided NVRAM data mapped by @p src.
|
||||
*
|
||||
* @param bcm A newly allocated data instance.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_bcm_init(struct bhnd_nvram_bcm *bcm, struct bhnd_nvram_io *src)
|
||||
{
|
||||
struct bhnd_nvram_bcmhdr hdr;
|
||||
uint8_t *p;
|
||||
void *ptr;
|
||||
size_t io_offset, io_size;
|
||||
uint8_t crc, valid;
|
||||
int error;
|
||||
|
||||
if ((error = bhnd_nvram_io_read(src, 0x0, &hdr, sizeof(hdr))))
|
||||
return (error);
|
||||
|
||||
if (le32toh(hdr.magic) != BCM_NVRAM_MAGIC)
|
||||
return (ENXIO);
|
||||
|
||||
/* Fetch the actual NVRAM image size */
|
||||
io_size = le32toh(hdr.size);
|
||||
if (io_size < sizeof(hdr)) {
|
||||
/* The header size must include the header itself */
|
||||
BHND_NV_LOG("corrupt header size: %zu\n", io_size);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (io_size > bhnd_nvram_io_getsize(src)) {
|
||||
BHND_NV_LOG("header size %zu exceeds input size %zu\n",
|
||||
io_size, bhnd_nvram_io_getsize(src));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Allocate a buffer large enough to hold the NVRAM image, and
|
||||
* an extra EOF-signaling NUL (on the chance it's missing from the
|
||||
* source data) */
|
||||
if (io_size == SIZE_MAX)
|
||||
return (ENOMEM);
|
||||
|
||||
bcm->data = bhnd_nvram_iobuf_empty(io_size, io_size + 1);
|
||||
if (bcm->data == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Fetch a pointer into our backing buffer and copy in the
|
||||
* NVRAM image. */
|
||||
error = bhnd_nvram_io_write_ptr(bcm->data, 0x0, &ptr, io_size, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
p = ptr;
|
||||
if ((error = bhnd_nvram_io_read(src, 0x0, p, io_size)))
|
||||
return (error);
|
||||
|
||||
/* Verify the CRC */
|
||||
valid = BCM_NVRAM_GET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_CRC);
|
||||
crc = bhnd_nvram_crc8(p + BCM_NVRAM_CRC_SKIP,
|
||||
io_size - BCM_NVRAM_CRC_SKIP, BHND_NVRAM_CRC8_INITIAL);
|
||||
|
||||
if (crc != valid) {
|
||||
BHND_NV_LOG("warning: NVRAM CRC error (crc=%#hhx, "
|
||||
"expected=%hhx)\n", crc, valid);
|
||||
}
|
||||
|
||||
/* Populate header variable definitions */
|
||||
#define BCM_READ_HDR_VAR(_name, _dest, _swap) do { \
|
||||
struct bhnd_nvram_bcm_hvar *data; \
|
||||
data = bhnd_nvram_bcm_gethdrvar(bcm, _name ##_VAR); \
|
||||
BHND_NV_ASSERT(data != NULL, \
|
||||
("no such header variable: " __STRING(_name))); \
|
||||
\
|
||||
\
|
||||
data->value. _dest = _swap(BCM_NVRAM_GET_BITS( \
|
||||
hdr. _name ## _FIELD, _name)); \
|
||||
} while(0)
|
||||
|
||||
BCM_READ_HDR_VAR(BCM_NVRAM_CFG0_SDRAM_INIT, u16, le16toh);
|
||||
BCM_READ_HDR_VAR(BCM_NVRAM_CFG1_SDRAM_CFG, u16, le16toh);
|
||||
BCM_READ_HDR_VAR(BCM_NVRAM_CFG1_SDRAM_REFRESH, u16, le16toh);
|
||||
BCM_READ_HDR_VAR(BCM_NVRAM_SDRAM_NCDL, u32, le32toh);
|
||||
|
||||
_Static_assert(nitems(bcm->hvars) == 4, "missing initialization for"
|
||||
"NVRAM header variable(s)");
|
||||
|
||||
#undef BCM_READ_HDR_VAR
|
||||
|
||||
/* Process the buffer */
|
||||
bcm->count = 0;
|
||||
io_offset = sizeof(hdr);
|
||||
while (io_offset < io_size) {
|
||||
char *envp;
|
||||
const char *name, *value;
|
||||
size_t envp_len;
|
||||
size_t name_len, value_len;
|
||||
|
||||
/* Parse the key=value string */
|
||||
envp = (char *) (p + io_offset);
|
||||
envp_len = strnlen(envp, io_size - io_offset);
|
||||
error = bhnd_nvram_parse_env(envp, envp_len, '=', &name,
|
||||
&name_len, &value, &value_len);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error parsing envp at offset %#zx: %d\n",
|
||||
io_offset, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Insert a '\0' character, replacing the '=' delimiter and
|
||||
* allowing us to vend references directly to the variable
|
||||
* name */
|
||||
*(envp + name_len) = '\0';
|
||||
|
||||
/* Record any NVRAM variables that mirror our header variables.
|
||||
* This is a brute-force search -- for the amount of data we're
|
||||
* operating on, it shouldn't be an issue. */
|
||||
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
|
||||
struct bhnd_nvram_bcm_hvar *hvar;
|
||||
union bhnd_nvram_bcm_hvar_value hval;
|
||||
size_t hval_len;
|
||||
|
||||
hvar = &bcm->hvars[i];
|
||||
|
||||
/* Already matched? */
|
||||
if (hvar->envp != NULL)
|
||||
continue;
|
||||
|
||||
/* Name matches? */
|
||||
if ((strcmp(name, hvar->name)) != 0)
|
||||
continue;
|
||||
|
||||
/* Save pointer to mirrored envp */
|
||||
hvar->envp = envp;
|
||||
|
||||
/* Check for stale value */
|
||||
hval_len = sizeof(hval);
|
||||
error = bhnd_nvram_value_coerce(value, value_len,
|
||||
BHND_NVRAM_TYPE_STRING, &hval, &hval_len,
|
||||
hvar->type);
|
||||
if (error) {
|
||||
/* If parsing fails, we can likely only make
|
||||
* things worse by trying to synchronize the
|
||||
* variables */
|
||||
BHND_NV_LOG("error parsing header variable "
|
||||
"'%s=%s': %d\n", name, value, error);
|
||||
} else if (hval_len != hvar->len) {
|
||||
hvar->stale = true;
|
||||
} else if (memcmp(&hval, &hvar->value, hval_len) != 0) {
|
||||
hvar->stale = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Seek past the value's terminating '\0' */
|
||||
io_offset += envp_len;
|
||||
if (io_offset == io_size) {
|
||||
BHND_NV_LOG("missing terminating NUL at offset %#zx\n",
|
||||
io_offset);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (*(p + io_offset) != '\0') {
|
||||
BHND_NV_LOG("invalid terminator '%#hhx' at offset "
|
||||
"%#zx\n", *(p + io_offset), io_offset);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Update variable count */
|
||||
bcm->count++;
|
||||
|
||||
/* Seek to the next record */
|
||||
if (++io_offset == io_size) {
|
||||
char ch;
|
||||
|
||||
/* Hit EOF without finding a terminating NUL
|
||||
* byte; we need to grow our buffer and append
|
||||
* it */
|
||||
io_size++;
|
||||
if ((error = bhnd_nvram_io_setsize(bcm->data, io_size)))
|
||||
return (error);
|
||||
|
||||
/* Write NUL byte */
|
||||
ch = '\0';
|
||||
error = bhnd_nvram_io_write(bcm->data, io_size-1, &ch,
|
||||
sizeof(ch));
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Check for explicit EOF (encoded as a single empty NUL
|
||||
* terminated string) */
|
||||
if (*(p + io_offset) == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add non-mirrored header variables to total count variable */
|
||||
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
|
||||
if (bcm->hvars[i].envp == NULL)
|
||||
bcm->count++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcm_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm;
|
||||
int error;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
|
||||
/* Populate default BCM mirrored header variable set */
|
||||
_Static_assert(sizeof(bcm->hvars) == sizeof(bhnd_nvram_bcm_hvars),
|
||||
"hvar declarations must match bhnd_nvram_bcm_hvars template");
|
||||
memcpy(bcm->hvars, bhnd_nvram_bcm_hvars, sizeof(bcm->hvars));
|
||||
|
||||
/* Parse the BCM input data and initialize our backing
|
||||
* data representation */
|
||||
if ((error = bhnd_nvram_bcm_init(bcm, io))) {
|
||||
bhnd_nvram_bcm_free(nv);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
bhnd_nvram_bcm_free(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
|
||||
if (bcm->data != NULL)
|
||||
bhnd_nvram_io_free(bcm->data);
|
||||
}
|
||||
|
||||
size_t
|
||||
bhnd_nvram_bcm_count(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
return (bcm->count);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcm_size(struct bhnd_nvram_data *nv, size_t *size)
|
||||
{
|
||||
return (bhnd_nvram_bcm_serialize(nv, NULL, size));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcm_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm;
|
||||
struct bhnd_nvram_bcmhdr hdr;
|
||||
void *cookiep;
|
||||
const char *name;
|
||||
size_t nbytes, limit;
|
||||
uint8_t crc;
|
||||
int error;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
nbytes = 0;
|
||||
|
||||
/* Save the output buffer limit */
|
||||
if (buf == NULL)
|
||||
limit = 0;
|
||||
else
|
||||
limit = *len;
|
||||
|
||||
/* Reserve space for the NVRAM header */
|
||||
nbytes += sizeof(struct bhnd_nvram_bcmhdr);
|
||||
|
||||
/* Write all variables to the output buffer */
|
||||
cookiep = NULL;
|
||||
while ((name = bhnd_nvram_data_next(nv, &cookiep))) {
|
||||
uint8_t *outp;
|
||||
size_t olen;
|
||||
size_t name_len, val_len;
|
||||
|
||||
if (limit > nbytes) {
|
||||
outp = (uint8_t *)buf + nbytes;
|
||||
olen = limit - nbytes;
|
||||
} else {
|
||||
outp = NULL;
|
||||
olen = 0;
|
||||
}
|
||||
|
||||
/* Determine length of variable name */
|
||||
name_len = strlen(name) + 1;
|
||||
|
||||
/* Write the variable name and '=' delimiter */
|
||||
if (olen >= name_len) {
|
||||
/* Copy name */
|
||||
memcpy(outp, name, name_len - 1);
|
||||
|
||||
/* Append '=' */
|
||||
*(outp + name_len - 1) = '=';
|
||||
}
|
||||
|
||||
/* Adjust byte counts */
|
||||
if (SIZE_MAX - name_len < nbytes)
|
||||
return (ERANGE);
|
||||
|
||||
nbytes += name_len;
|
||||
|
||||
/* Reposition output */
|
||||
if (limit > nbytes) {
|
||||
outp = (uint8_t *)buf + nbytes;
|
||||
olen = limit - nbytes;
|
||||
} else {
|
||||
outp = NULL;
|
||||
olen = 0;
|
||||
}
|
||||
|
||||
/* Coerce to NUL-terminated C string, writing to the output
|
||||
* buffer (or just calculating the length if outp is NULL) */
|
||||
val_len = olen;
|
||||
error = bhnd_nvram_data_getvar(nv, cookiep, outp, &val_len,
|
||||
BHND_NVRAM_TYPE_STRING);
|
||||
|
||||
if (error && error != ENOMEM)
|
||||
return (error);
|
||||
|
||||
/* Adjust byte counts */
|
||||
if (SIZE_MAX - val_len < nbytes)
|
||||
return (ERANGE);
|
||||
|
||||
nbytes += val_len;
|
||||
}
|
||||
|
||||
/* Write terminating NUL */
|
||||
if (nbytes < limit)
|
||||
*((uint8_t *)buf + nbytes) = '\0';
|
||||
nbytes++;
|
||||
|
||||
/* Provide actual size */
|
||||
*len = nbytes;
|
||||
if (buf == NULL || nbytes > limit) {
|
||||
if (buf != NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Fetch current NVRAM header */
|
||||
if ((error = bhnd_nvram_io_read(bcm->data, 0x0, &hdr, sizeof(hdr))))
|
||||
return (error);
|
||||
|
||||
/* Update values covered by CRC and write to output buffer */
|
||||
hdr.size = htole32(*len);
|
||||
memcpy(buf, &hdr, sizeof(hdr));
|
||||
|
||||
/* Calculate new CRC */
|
||||
crc = bhnd_nvram_crc8((uint8_t *)buf + BCM_NVRAM_CRC_SKIP,
|
||||
*len - BCM_NVRAM_CRC_SKIP, BHND_NVRAM_CRC8_INITIAL);
|
||||
|
||||
/* Update header with valid CRC */
|
||||
hdr.cfg0 &= ~BCM_NVRAM_CFG0_CRC_MASK;
|
||||
hdr.cfg0 |= (crc << BCM_NVRAM_CFG0_CRC_SHIFT);
|
||||
memcpy(buf, &hdr, sizeof(hdr));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
bhnd_nvram_bcm_caps(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_bcm_next(struct bhnd_nvram_data *nv, void **cookiep)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm;
|
||||
struct bhnd_nvram_bcm_hvar *hvar, *hvar_next;
|
||||
const void *ptr;
|
||||
const char *envp, *basep;
|
||||
size_t io_size, io_offset;
|
||||
int error;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
|
||||
io_offset = sizeof(struct bhnd_nvram_bcmhdr);
|
||||
io_size = bhnd_nvram_io_getsize(bcm->data) - io_offset;
|
||||
|
||||
/* Map backing buffer */
|
||||
error = bhnd_nvram_io_read_ptr(bcm->data, io_offset, &ptr, io_size,
|
||||
NULL);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error mapping backing buffer: %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
basep = ptr;
|
||||
|
||||
/* If cookiep pointers into our header variable array, handle as header
|
||||
* variable iteration. */
|
||||
hvar = bhnd_nvram_bcm_to_hdrvar(bcm, *cookiep);
|
||||
if (hvar != NULL) {
|
||||
size_t idx;
|
||||
|
||||
/* Advance to next entry, if any */
|
||||
idx = bhnd_nvram_bcm_hdrvar_index(bcm, hvar) + 1;
|
||||
|
||||
/* Find the next header-defined variable that isn't defined in
|
||||
* the NVRAM data, start iteration there */
|
||||
for (size_t i = idx; i < nitems(bcm->hvars); i++) {
|
||||
hvar_next = &bcm->hvars[i];
|
||||
if (hvar_next->envp != NULL && !hvar_next->stale)
|
||||
continue;
|
||||
|
||||
*cookiep = hvar_next;
|
||||
return (hvar_next->name);
|
||||
}
|
||||
|
||||
/* No further header-defined variables; iteration
|
||||
* complete */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Handle standard NVRAM data iteration */
|
||||
if (*cookiep == NULL) {
|
||||
/* Start at the first NVRAM data record */
|
||||
envp = basep;
|
||||
} else {
|
||||
/* Seek to next record */
|
||||
envp = *cookiep;
|
||||
envp += strlen(envp) + 1; /* key + '\0' */
|
||||
envp += strlen(envp) + 1; /* value + '\0' */
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip entries that have an existing header variable entry that takes
|
||||
* precedence over the NVRAM data value.
|
||||
*
|
||||
* The header's value will be provided when performing header variable
|
||||
* iteration
|
||||
*/
|
||||
while ((size_t)(envp - basep) < io_size && *envp != '\0') {
|
||||
/* Locate corresponding header variable */
|
||||
hvar = NULL;
|
||||
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
|
||||
if (bcm->hvars[i].envp != envp)
|
||||
continue;
|
||||
|
||||
hvar = &bcm->hvars[i];
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no corresponding hvar entry, or the entry does not take
|
||||
* precedence over this NVRAM value, we can safely return this
|
||||
* value as-is. */
|
||||
if (hvar == NULL || !hvar->stale)
|
||||
break;
|
||||
|
||||
/* Seek to next record */
|
||||
envp += strlen(envp) + 1; /* key + '\0' */
|
||||
envp += strlen(envp) + 1; /* value + '\0' */
|
||||
}
|
||||
|
||||
/* On NVRAM data EOF, try switching to header variables */
|
||||
if ((size_t)(envp - basep) == io_size || *envp == '\0') {
|
||||
/* Find first valid header variable */
|
||||
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
|
||||
if (bcm->hvars[i].envp != NULL)
|
||||
continue;
|
||||
|
||||
*cookiep = &bcm->hvars[i];
|
||||
return (bcm->hvars[i].name);
|
||||
}
|
||||
|
||||
/* No header variables */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*cookiep = (void *)(uintptr_t)envp;
|
||||
return (envp);
|
||||
}
|
||||
|
||||
static void *
|
||||
bhnd_nvram_bcm_find(struct bhnd_nvram_data *nv, const char *name)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_find(nv, name));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcm_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
|
||||
}
|
||||
|
||||
static const void *
|
||||
bhnd_nvram_bcm_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
size_t *len, bhnd_nvram_type *type)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm;
|
||||
struct bhnd_nvram_bcm_hvar *hvar;
|
||||
const char *envp;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
|
||||
/* Handle header variables */
|
||||
if ((hvar = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep)) != NULL) {
|
||||
BHND_NV_ASSERT(
|
||||
hvar->len % bhnd_nvram_value_size(hvar->type, NULL, 0,
|
||||
hvar->nelem) == 0,
|
||||
("length is not aligned to type width"));
|
||||
|
||||
*type = hvar->type;
|
||||
*len = hvar->len;
|
||||
return (&hvar->value);
|
||||
}
|
||||
|
||||
/* Cookie points to key\0value\0 -- get the value address */
|
||||
BHND_NV_ASSERT(cookiep != NULL, ("NULL cookiep"));
|
||||
|
||||
envp = cookiep;
|
||||
envp += strlen(envp) + 1; /* key + '\0' */
|
||||
*len = strlen(envp) + 1; /* value + '\0' */
|
||||
*type = BHND_NVRAM_TYPE_STRING;
|
||||
|
||||
return (envp);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_bcm_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
|
||||
{
|
||||
struct bhnd_nvram_bcm *bcm;
|
||||
struct bhnd_nvram_bcm_hvar *hvar;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcm *)nv;
|
||||
|
||||
/* Handle header variables */
|
||||
if ((hvar = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep)) != NULL) {
|
||||
return (hvar->name);
|
||||
}
|
||||
|
||||
/* Cookie points to key\0value\0 */
|
||||
return (cookiep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal BCM data reference for a header-defined variable
|
||||
* with @p name, or NULL if none exists.
|
||||
*/
|
||||
static struct bhnd_nvram_bcm_hvar *
|
||||
bhnd_nvram_bcm_gethdrvar(struct bhnd_nvram_bcm *bcm, const char *name)
|
||||
{
|
||||
for (size_t i = 0; i < nitems(bcm->hvars); i++) {
|
||||
if (strcmp(bcm->hvars[i].name, name) == 0)
|
||||
return (&bcm->hvars[i]);
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* If @p cookiep references a header-defined variable, return the
|
||||
* internal BCM data reference. Otherwise, returns NULL.
|
||||
*/
|
||||
static struct bhnd_nvram_bcm_hvar *
|
||||
bhnd_nvram_bcm_to_hdrvar(struct bhnd_nvram_bcm *bcm, void *cookiep)
|
||||
{
|
||||
#ifdef BHND_NVRAM_INVARIANTS
|
||||
uintptr_t base, ptr;
|
||||
#endif
|
||||
|
||||
/* If the cookie falls within the hvar array, it's a
|
||||
* header variable cookie */
|
||||
if (nitems(bcm->hvars) == 0)
|
||||
return (NULL);
|
||||
|
||||
if (cookiep < (void *)&bcm->hvars[0])
|
||||
return (NULL);
|
||||
|
||||
if (cookiep > (void *)&bcm->hvars[nitems(bcm->hvars)-1])
|
||||
return (NULL);
|
||||
|
||||
#ifdef BHND_NVRAM_INVARIANTS
|
||||
base = (uintptr_t)bcm->hvars;
|
||||
ptr = (uintptr_t)cookiep;
|
||||
|
||||
BHND_NV_ASSERT((ptr - base) % sizeof(bcm->hvars[0]) == 0,
|
||||
("misaligned hvar pointer %p/%p", cookiep, bcm->hvars));
|
||||
#endif /* INVARIANTS */
|
||||
|
||||
return ((struct bhnd_nvram_bcm_hvar *)cookiep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of @p hdrvar within @p bcm's backing hvars array.
|
||||
*/
|
||||
static size_t
|
||||
bhnd_nvram_bcm_hdrvar_index(struct bhnd_nvram_bcm *bcm,
|
||||
struct bhnd_nvram_bcm_hvar *hdrvar)
|
||||
{
|
||||
BHND_NV_ASSERT(bhnd_nvram_bcm_to_hdrvar(bcm, (void *)hdrvar) != NULL,
|
||||
("%p is not a valid hdrvar reference", hdrvar));
|
||||
|
||||
return (hdrvar - &bcm->hvars[0]);
|
||||
}
|
380
sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
Normal file
380
sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
Normal file
@ -0,0 +1,380 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
|
||||
/*
|
||||
* Broadcom-RAW NVRAM data class.
|
||||
*
|
||||
* The Broadcom NVRAM NUL-delimited ASCII format is used by most
|
||||
* Broadcom SoCs.
|
||||
*
|
||||
* The NVRAM data is encoded as a stream of of NUL-terminated 'key=value'
|
||||
* strings; the end of the stream is denoted by a single extra NUL character.
|
||||
*/
|
||||
|
||||
struct bhnd_nvram_bcmraw;
|
||||
|
||||
/** BCM-RAW NVRAM data class instance */
|
||||
struct bhnd_nvram_bcmraw {
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
char *data; /**< backing buffer */
|
||||
size_t size; /**< buffer size */
|
||||
size_t count; /**< variable count */
|
||||
};
|
||||
|
||||
BHND_NVRAM_DATA_CLASS_DEFN(bcmraw, "Broadcom (RAW)",
|
||||
sizeof(struct bhnd_nvram_bcmraw))
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcmraw_probe(struct bhnd_nvram_io *io)
|
||||
{
|
||||
char envp[16];
|
||||
size_t envp_len;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Fetch the initial bytes to try to identify BCM data.
|
||||
*
|
||||
* We always assert a low probe priority, as we only scan the initial
|
||||
* bytes of the file.
|
||||
*/
|
||||
envp_len = bhnd_nv_ummin(sizeof(envp), bhnd_nvram_io_getsize(io));
|
||||
if ((error = bhnd_nvram_io_read(io, 0x0, envp, envp_len)))
|
||||
return (error);
|
||||
|
||||
/* A zero-length BCM-RAW buffer should contain a single terminating
|
||||
* NUL */
|
||||
if (envp_len == 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (envp_len == 1) {
|
||||
if (envp[0] != '\0')
|
||||
return (ENXIO);
|
||||
|
||||
return (BHND_NVRAM_DATA_PROBE_MAYBE);
|
||||
}
|
||||
|
||||
/* Don't match on non-ASCII, non-printable data */
|
||||
for (size_t i = 0; i < envp_len; i++) {
|
||||
char c = envp[i];
|
||||
if (envp[i] == '\0')
|
||||
break;
|
||||
|
||||
if (!bhnd_nv_isprint(c))
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* The first character should be a valid key char */
|
||||
if (!bhnd_nv_isalpha(envp[0]))
|
||||
return (ENXIO);
|
||||
|
||||
return (BHND_NVRAM_DATA_PROBE_MAYBE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize @p bcm with the provided NVRAM data mapped by @p src.
|
||||
*
|
||||
* @param bcm A newly allocated data instance.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_bcmraw_init(struct bhnd_nvram_bcmraw *bcm, struct bhnd_nvram_io *src)
|
||||
{
|
||||
size_t io_size;
|
||||
size_t capacity, offset;
|
||||
int error;
|
||||
|
||||
/* Fetch the input image size */
|
||||
io_size = bhnd_nvram_io_getsize(src);
|
||||
|
||||
/* Allocate a buffer large enough to hold the NVRAM image, and
|
||||
* an extra EOF-signaling NUL (on the chance it's missing from the
|
||||
* source data) */
|
||||
if (io_size == SIZE_MAX)
|
||||
return (ENOMEM);
|
||||
|
||||
capacity = io_size + 1 /* room for extra NUL */;
|
||||
bcm->size = io_size;
|
||||
if ((bcm->data = bhnd_nv_malloc(capacity)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Copy in the NVRAM image */
|
||||
if ((error = bhnd_nvram_io_read(src, 0x0, bcm->data, io_size)))
|
||||
return (error);
|
||||
|
||||
/* Process the buffer */
|
||||
bcm->count = 0;
|
||||
for (offset = 0; offset < bcm->size; offset++) {
|
||||
char *envp;
|
||||
const char *name, *value;
|
||||
size_t envp_len;
|
||||
size_t name_len, value_len;
|
||||
|
||||
/* Parse the key=value string */
|
||||
envp = (char *) (bcm->data + offset);
|
||||
envp_len = strnlen(envp, bcm->size - offset);
|
||||
error = bhnd_nvram_parse_env(envp, envp_len, '=', &name,
|
||||
&name_len, &value, &value_len);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error parsing envp at offset %#zx: %d\n",
|
||||
offset, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Insert a '\0' character, replacing the '=' delimiter and
|
||||
* allowing us to vend references directly to the variable
|
||||
* name */
|
||||
*(envp + name_len) = '\0';
|
||||
|
||||
/* Add to variable count */
|
||||
bcm->count++;
|
||||
|
||||
/* Seek past the value's terminating '\0' */
|
||||
offset += envp_len;
|
||||
if (offset == io_size) {
|
||||
BHND_NV_LOG("missing terminating NUL at offset %#zx\n",
|
||||
offset);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* If we hit EOF without finding a terminating NUL
|
||||
* byte, we need to append it */
|
||||
if (++offset == bcm->size) {
|
||||
BHND_NV_ASSERT(offset < capacity,
|
||||
("appending past end of buffer"));
|
||||
bcm->size++;
|
||||
*(bcm->data + offset) = '\0';
|
||||
}
|
||||
|
||||
/* Check for explicit EOF (encoded as a single empty NUL
|
||||
* terminated string) */
|
||||
if (*(bcm->data + offset) == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reclaim any unused space in he backing buffer */
|
||||
if (offset < bcm->size) {
|
||||
bcm->data = bhnd_nv_reallocf(bcm->data, bcm->size);
|
||||
if (bcm->data == NULL)
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcmraw_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_bcmraw *bcm;
|
||||
int error;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcmraw *)nv;
|
||||
|
||||
/* Parse the BCM input data and initialize our backing
|
||||
* data representation */
|
||||
if ((error = bhnd_nvram_bcmraw_init(bcm, io))) {
|
||||
bhnd_nvram_bcmraw_free(nv);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
bhnd_nvram_bcmraw_free(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
|
||||
|
||||
if (bcm->data != NULL)
|
||||
bhnd_nv_free(bcm->data);
|
||||
}
|
||||
|
||||
static size_t
|
||||
bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
|
||||
|
||||
return (bcm->count);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcmraw_size(struct bhnd_nvram_data *nv, size_t *size)
|
||||
{
|
||||
return (bhnd_nvram_bcmraw_serialize(nv, NULL, size));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcmraw_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
|
||||
{
|
||||
struct bhnd_nvram_bcmraw *bcm;
|
||||
char * const p = (char *)buf;
|
||||
size_t limit;
|
||||
size_t offset;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcmraw *)nv;
|
||||
|
||||
/* Save the output buffer limit */
|
||||
if (buf == NULL)
|
||||
limit = 0;
|
||||
else
|
||||
limit = *len;
|
||||
|
||||
/* The serialized form will be exactly the length
|
||||
* of our backing buffer representation */
|
||||
*len = bcm->size;
|
||||
|
||||
/* Skip serialization if not requested, or report ENOMEM if
|
||||
* buffer is too small */
|
||||
if (buf == NULL) {
|
||||
return (0);
|
||||
} else if (*len > limit) {
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
/* Write all variables to the output buffer */
|
||||
memcpy(buf, bcm->data, *len);
|
||||
|
||||
/* Rewrite all '\0' delimiters back to '=' */
|
||||
offset = 0;
|
||||
while (offset < bcm->size) {
|
||||
size_t name_len, value_len;
|
||||
|
||||
name_len = strlen(p + offset);
|
||||
|
||||
/* EOF? */
|
||||
if (name_len == 0) {
|
||||
BHND_NV_ASSERT(*(p + offset) == '\0',
|
||||
("no NUL terminator"));
|
||||
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Rewrite 'name\0' to 'name=' */
|
||||
offset += name_len;
|
||||
BHND_NV_ASSERT(*(p + offset) == '\0', ("incorrect offset"));
|
||||
|
||||
*(p + offset) = '=';
|
||||
offset++;
|
||||
|
||||
value_len = strlen(p + offset);
|
||||
offset += value_len + 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
bhnd_nvram_bcmraw_caps(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_bcmraw_next(struct bhnd_nvram_data *nv, void **cookiep)
|
||||
{
|
||||
struct bhnd_nvram_bcmraw *bcm;
|
||||
const char *envp;
|
||||
|
||||
bcm = (struct bhnd_nvram_bcmraw *)nv;
|
||||
|
||||
if (*cookiep == NULL) {
|
||||
/* Start at the first NVRAM data record */
|
||||
envp = bcm->data;
|
||||
} else {
|
||||
/* Seek to next record */
|
||||
envp = *cookiep;
|
||||
envp += strlen(envp) + 1; /* key + '\0' */
|
||||
envp += strlen(envp) + 1; /* value + '\0' */
|
||||
}
|
||||
|
||||
/* EOF? */
|
||||
if (*envp == '\0')
|
||||
return (NULL);
|
||||
|
||||
*cookiep = (void *)(uintptr_t)envp;
|
||||
return (envp);
|
||||
}
|
||||
|
||||
static void *
|
||||
bhnd_nvram_bcmraw_find(struct bhnd_nvram_data *nv, const char *name)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_find(nv, name));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcmraw_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
|
||||
}
|
||||
|
||||
static const void *
|
||||
bhnd_nvram_bcmraw_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
size_t *len, bhnd_nvram_type *type)
|
||||
{
|
||||
const char *envp;
|
||||
|
||||
/* Cookie points to key\0value\0 -- get the value address */
|
||||
envp = cookiep;
|
||||
envp += strlen(envp) + 1; /* key + '\0' */
|
||||
*len = strlen(envp) + 1; /* value + '\0' */
|
||||
*type = BHND_NVRAM_TYPE_STRING;
|
||||
|
||||
return (envp);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_bcmraw_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
|
||||
{
|
||||
/* Cookie points to key\0value\0 */
|
||||
return (cookiep);
|
||||
}
|
73
sys/dev/bhnd/nvram/bhnd_nvram_data_bcmreg.h
Normal file
73
sys/dev/bhnd/nvram/bhnd_nvram_data_bcmreg.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_BCMREG_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_BCMREG_H_
|
||||
|
||||
#define BCM_NVRAM_GET_BITS(_value, _field) \
|
||||
((_value & _field ## _MASK) >> _field ## _SHIFT)
|
||||
|
||||
/* BCM NVRAM header fields */
|
||||
#define BCM_NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
|
||||
#define BCM_NVRAM_VERSION 1
|
||||
|
||||
#define BCM_NVRAM_CRC_SKIP 9 /* skip magic, size, and crc8 */
|
||||
|
||||
#define BCM_NVRAM_CFG0_CRC_MASK 0x000000FF
|
||||
#define BCM_NVRAM_CFG0_CRC_SHIFT 0
|
||||
#define BCM_NVRAM_CFG0_VER_MASK 0x0000FF00
|
||||
#define BCM_NVRAM_CFG0_VER_SHIFT 8
|
||||
|
||||
#define BCM_NVRAM_CFG0_SDRAM_INIT_FIELD cfg0
|
||||
#define BCM_NVRAM_CFG0_SDRAM_INIT_MASK 0xFFFF0000
|
||||
#define BCM_NVRAM_CFG0_SDRAM_INIT_SHIFT 16
|
||||
#define BCM_NVRAM_CFG0_SDRAM_INIT_VAR "sdram_init"
|
||||
#define BCM_NVRAM_CFG0_SDRAM_INIT_FMT "0x%04x"
|
||||
|
||||
#define BCM_NVRAM_CFG1_SDRAM_CFG_FIELD cfg1
|
||||
#define BCM_NVRAM_CFG1_SDRAM_CFG_MASK 0x0000FFFF
|
||||
#define BCM_NVRAM_CFG1_SDRAM_CFG_SHIFT 0
|
||||
#define BCM_NVRAM_CFG1_SDRAM_CFG_VAR "sdram_config"
|
||||
#define BCM_NVRAM_CFG1_SDRAM_CFG_FMT "0x%04x"
|
||||
|
||||
#define BCM_NVRAM_CFG1_SDRAM_REFRESH_FIELD cfg1
|
||||
#define BCM_NVRAM_CFG1_SDRAM_REFRESH_MASK 0xFFFF0000
|
||||
#define BCM_NVRAM_CFG1_SDRAM_REFRESH_SHIFT 16
|
||||
#define BCM_NVRAM_CFG1_SDRAM_REFRESH_VAR "sdram_refresh"
|
||||
#define BCM_NVRAM_CFG1_SDRAM_REFRESH_FMT "0x%04x"
|
||||
|
||||
#define BCM_NVRAM_SDRAM_NCDL_FIELD sdram_ncdl
|
||||
#define BCM_NVRAM_SDRAM_NCDL_MASK UINT32_MAX
|
||||
#define BCM_NVRAM_SDRAM_NCDL_SHIFT 0
|
||||
#define BCM_NVRAM_SDRAM_NCDL_VAR "sdram_ncdl"
|
||||
#define BCM_NVRAM_SDRAM_NCDL_FMT "0x%08x"
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_BCMREG_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landon@landonf.org>
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -25,40 +25,46 @@
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_SPROM_PARSERVAR_H_
|
||||
#define _BHND_NVRAM_SPROM_PARSERVAR_H_
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_BCMVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_BCMVAR_H_
|
||||
|
||||
#include "bhnd_sprom_parser.h"
|
||||
/**
|
||||
* BCM NVRAM header value data.
|
||||
*/
|
||||
union bhnd_nvram_bcm_hvar_value {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
};
|
||||
|
||||
#define SPROM_SZ_R1_3 128 /**< SPROM image size (rev 1-3) */
|
||||
#define SPROM_SZ_R4_8_9 440 /**< SPROM image size (rev 4, 8-9) */
|
||||
#define SPROM_SZ_R10 460 /**< SPROM image size (rev 10) */
|
||||
#define SPROM_SZ_R11 468 /**< SPROM image size (rev 11) */
|
||||
/**
|
||||
* Internal representation of BCM NVRAM values that mirror (and must be
|
||||
* vended as) NVRAM variables.
|
||||
*/
|
||||
struct bhnd_nvram_bcm_hvar {
|
||||
const char *name; /**< variable name */
|
||||
bhnd_nvram_type type; /**< value type */
|
||||
size_t nelem; /**< value element count */
|
||||
size_t len; /**< value length */
|
||||
const char *envp; /**< Pointer to the NVRAM variable mirroring
|
||||
this header value, or NULL. */
|
||||
bool stale; /**< header value does not match
|
||||
mirrored NVRAM value */
|
||||
|
||||
/** Maximum supported SPROM image size */
|
||||
#define SPROM_SZ_MAX SPROM_SZ_R11
|
||||
/** variable data */
|
||||
union bhnd_nvram_bcm_hvar_value value;
|
||||
};
|
||||
|
||||
/** BCM NVRAM header */
|
||||
struct bhnd_nvram_bcmhdr {
|
||||
uint32_t magic;
|
||||
uint32_t size;
|
||||
uint32_t cfg0; /**< crc:8, version:8, sdram_init:16 */
|
||||
uint32_t cfg1; /**< sdram_config:16, sdram_refresh:16 */
|
||||
uint32_t sdram_ncdl; /**< sdram_ncdl */
|
||||
} __packed;
|
||||
|
||||
#define SPROM_SIG_NONE 0x0
|
||||
#define SPROM_SIG_NONE_OFF 0x0
|
||||
|
||||
/** SPROM signature (rev 4) */
|
||||
#define SPROM_SIG_R4 0x5372
|
||||
#define SPROM_SIG_R4_OFF 64 /**< SPROM signature offset (rev 4) */
|
||||
|
||||
/** SPROM signature (rev 8, 9) */
|
||||
#define SPROM_SIG_R8_9 SPROM_SIG_R4
|
||||
#define SPROM_SIG_R8_9_OFF 128 /**< SPROM signature offset (rev 8-9) */
|
||||
|
||||
/** SPROM signature (rev 10) */
|
||||
#define SPROM_SIG_R10 SPROM_SIG_R4
|
||||
#define SPROM_SIG_R10_OFF 438 /**< SPROM signature offset (rev 10) */
|
||||
|
||||
/** SPROM signature (rev 11) */
|
||||
#define SPROM_SIG_R11 0x0634
|
||||
#define SPROM_SIG_R11_OFF 128 /**< SPROM signature offset (rev 11) */
|
||||
|
||||
#endif /* _BHND_NVRAM_SPROM_PARSERVAR_H_ */
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_BCMVAR_H_ */
|
586
sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
Normal file
586
sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
Normal file
@ -0,0 +1,586 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/endian.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
|
||||
#include "bhnd_nvram_data_bcmreg.h" /* for BCM_NVRAM_MAGIC */
|
||||
|
||||
/**
|
||||
* Broadcom "Board Text" data class.
|
||||
*
|
||||
* This format is used to provide external NVRAM data for some
|
||||
* fullmac WiFi devices, and as an input format when programming
|
||||
* NVRAM/SPROM/OTP.
|
||||
*/
|
||||
|
||||
struct bhnd_nvram_btxt {
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
struct bhnd_nvram_io *data; /**< memory-backed board text data */
|
||||
size_t count; /**< variable count */
|
||||
};
|
||||
|
||||
BHND_NVRAM_DATA_CLASS_DEFN(btxt, "Broadcom Board Text",
|
||||
sizeof(struct bhnd_nvram_btxt))
|
||||
|
||||
/** Minimal identification header */
|
||||
union bhnd_nvram_btxt_ident {
|
||||
uint32_t bcm_magic;
|
||||
char btxt[8];
|
||||
};
|
||||
|
||||
static size_t bhnd_nvram_btxt_io_offset(struct bhnd_nvram_btxt *btxt,
|
||||
void *cookiep);
|
||||
|
||||
static int bhnd_nvram_btxt_entry_len(struct bhnd_nvram_io *io,
|
||||
size_t offset, size_t *line_len, size_t *env_len);
|
||||
static int bhnd_nvram_btxt_seek_next(struct bhnd_nvram_io *io,
|
||||
size_t *offset);
|
||||
static int bhnd_nvram_btxt_seek_eol(struct bhnd_nvram_io *io,
|
||||
size_t *offset);
|
||||
|
||||
static int
|
||||
bhnd_nvram_btxt_probe(struct bhnd_nvram_io *io)
|
||||
{
|
||||
union bhnd_nvram_btxt_ident ident;
|
||||
char c;
|
||||
int error;
|
||||
|
||||
/* Look at the initial header for something that looks like
|
||||
* an ASCII board text file */
|
||||
if ((error = bhnd_nvram_io_read(io, 0x0, &ident, sizeof(ident))))
|
||||
return (error);
|
||||
|
||||
/* The BCM NVRAM format uses a 'FLSH' little endian magic value, which
|
||||
* shouldn't be interpreted as BTXT */
|
||||
if (le32toh(ident.bcm_magic) == BCM_NVRAM_MAGIC)
|
||||
return (ENXIO);
|
||||
|
||||
/* Don't match on non-ASCII/non-printable data */
|
||||
for (size_t i = 0; i < nitems(ident.btxt); i++) {
|
||||
c = ident.btxt[i];
|
||||
if (!bhnd_nv_isprint(c))
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* The first character should either be a valid key char (alpha),
|
||||
* whitespace, or the start of a comment ('#') */
|
||||
c = ident.btxt[0];
|
||||
if (!bhnd_nv_isspace(c) && !bhnd_nv_isalpha(c) && c != '#')
|
||||
return (ENXIO);
|
||||
|
||||
/* We assert a low priority, given that we've only scanned an
|
||||
* initial few bytes of the file. */
|
||||
return (BHND_NVRAM_DATA_PROBE_MAYBE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize @p btxt with the provided board text data mapped by @p src.
|
||||
*
|
||||
* @param btxt A newly allocated data instance.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_btxt_init(struct bhnd_nvram_btxt *btxt, struct bhnd_nvram_io *src)
|
||||
{
|
||||
const void *ptr;
|
||||
const char *name, *value;
|
||||
size_t name_len, value_len;
|
||||
size_t line_len, env_len;
|
||||
size_t io_offset, io_size, str_size;
|
||||
int error;
|
||||
|
||||
BHND_NV_ASSERT(btxt->data == NULL, ("btxt data already allocated"));
|
||||
|
||||
if ((btxt->data = bhnd_nvram_iobuf_copy(src)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(btxt->data);
|
||||
io_offset = 0;
|
||||
|
||||
/* Fetch a pointer mapping the entirity of the board text data */
|
||||
error = bhnd_nvram_io_read_ptr(btxt->data, 0x0, &ptr, io_size, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Determine the actual size, minus any terminating NUL. We
|
||||
* parse NUL-terminated C strings, but do not include NUL termination
|
||||
* in our internal or serialized representations */
|
||||
str_size = strnlen(ptr, io_size);
|
||||
|
||||
/* If the terminating NUL is not found at the end of the buffer,
|
||||
* this is BCM-RAW or other NUL-delimited NVRAM format. */
|
||||
if (str_size < io_size && str_size + 1 < io_size)
|
||||
return (EINVAL);
|
||||
|
||||
/* Adjust buffer size to account for NUL termination (if any) */
|
||||
io_size = str_size;
|
||||
if ((error = bhnd_nvram_io_setsize(btxt->data, io_size)))
|
||||
return (error);
|
||||
|
||||
/* Process the buffer */
|
||||
btxt->count = 0;
|
||||
while (io_offset < io_size) {
|
||||
const void *envp;
|
||||
|
||||
/* Seek to the next key=value entry */
|
||||
if ((error = bhnd_nvram_btxt_seek_next(btxt->data, &io_offset)))
|
||||
return (error);
|
||||
|
||||
/* Determine the entry and line length */
|
||||
error = bhnd_nvram_btxt_entry_len(btxt->data, io_offset,
|
||||
&line_len, &env_len);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* EOF? */
|
||||
if (env_len == 0) {
|
||||
BHND_NV_ASSERT(io_offset == io_size,
|
||||
("zero-length record returned from "
|
||||
"bhnd_nvram_btxt_seek_next()"));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fetch a pointer to the line start */
|
||||
error = bhnd_nvram_io_read_ptr(btxt->data, io_offset, &envp,
|
||||
env_len, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Parse the key=value string */
|
||||
error = bhnd_nvram_parse_env(envp, env_len, '=', &name,
|
||||
&name_len, &value, &value_len);
|
||||
if (error) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Insert a '\0' character, replacing the '=' delimiter and
|
||||
* allowing us to vend references directly to the variable
|
||||
* name */
|
||||
error = bhnd_nvram_io_write(btxt->data, io_offset+name_len,
|
||||
&(char){'\0'}, 1);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Add to variable count */
|
||||
btxt->count++;
|
||||
|
||||
/* Advance past EOL */
|
||||
io_offset += line_len;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_btxt_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt;
|
||||
int error;
|
||||
|
||||
/* Allocate and initialize the BTXT data instance */
|
||||
btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
|
||||
/* Parse the BTXT input data and initialize our backing
|
||||
* data representation */
|
||||
if ((error = bhnd_nvram_btxt_init(btxt, io))) {
|
||||
bhnd_nvram_btxt_free(nv);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
bhnd_nvram_btxt_free(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
if (btxt->data != NULL)
|
||||
bhnd_nvram_io_free(btxt->data);
|
||||
}
|
||||
|
||||
size_t
|
||||
bhnd_nvram_btxt_count(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
return (btxt->count);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_btxt_size(struct bhnd_nvram_data *nv, size_t *size)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
|
||||
/* The serialized form will be identical in length
|
||||
* to our backing buffer representation */
|
||||
*size = bhnd_nvram_io_getsize(btxt->data);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_btxt_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt;
|
||||
size_t limit;
|
||||
int error;
|
||||
|
||||
btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
|
||||
limit = *len;
|
||||
|
||||
/* Provide actual output size */
|
||||
if ((error = bhnd_nvram_data_size(nv, len)))
|
||||
return (error);
|
||||
|
||||
if (buf == NULL) {
|
||||
return (0);
|
||||
} else if (limit < *len) {
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
/* Copy our internal representation to the output buffer */
|
||||
if ((error = bhnd_nvram_io_read(btxt->data, 0x0, buf, *len)))
|
||||
return (error);
|
||||
|
||||
/* Restore the original key=value format, rewriting all '\0'
|
||||
* key\0value delimiters back to '=' */
|
||||
for (char *p = buf; (size_t)(p - (char *)buf) < *len; p++) {
|
||||
if (*p == '\0')
|
||||
*p = '=';
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
bhnd_nvram_btxt_caps(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
|
||||
}
|
||||
|
||||
static void *
|
||||
bhnd_nvram_btxt_find(struct bhnd_nvram_data *nv, const char *name)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_find(nv, name));
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_btxt_next(struct bhnd_nvram_data *nv, void **cookiep)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt;
|
||||
const void *nptr;
|
||||
size_t io_offset, io_size;
|
||||
int error;
|
||||
|
||||
btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(btxt->data);
|
||||
io_offset = bhnd_nvram_btxt_io_offset(btxt, *cookiep);
|
||||
|
||||
/* Already at EOF? */
|
||||
if (io_offset == io_size)
|
||||
return (NULL);
|
||||
|
||||
/* Seek to the next entry (if any) */
|
||||
if ((error = bhnd_nvram_btxt_seek_eol(btxt->data, &io_offset))) {
|
||||
BHND_NV_LOG("unexpected error in seek_eol(): %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((error = bhnd_nvram_btxt_seek_next(btxt->data, &io_offset))) {
|
||||
BHND_NV_LOG("unexpected error in seek_next(): %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Provide the new cookie for this offset */
|
||||
if (io_offset > UINTPTR_MAX) {
|
||||
BHND_NV_LOG("io_offset > UINPTR_MAX!\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*cookiep = (void *)(uintptr_t)io_offset;
|
||||
|
||||
/* Hit EOF? */
|
||||
if (io_offset == io_size)
|
||||
return (NULL);
|
||||
|
||||
/* Fetch the name pointer; it must be at least 1 byte long */
|
||||
error = bhnd_nvram_io_read_ptr(btxt->data, io_offset, &nptr, 1, NULL);
|
||||
if (error) {
|
||||
BHND_NV_LOG("unexpected error in read_ptr(): %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Return the name pointer */
|
||||
return (nptr);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_btxt_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
|
||||
}
|
||||
|
||||
const void *
|
||||
bhnd_nvram_btxt_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
size_t *len, bhnd_nvram_type *type)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt;
|
||||
const void *eptr;
|
||||
const char *vptr;
|
||||
size_t io_offset, io_size;
|
||||
size_t line_len, env_len;
|
||||
int error;
|
||||
|
||||
btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(btxt->data);
|
||||
io_offset = bhnd_nvram_btxt_io_offset(btxt, cookiep);
|
||||
|
||||
/* At EOF? */
|
||||
if (io_offset == io_size)
|
||||
return (NULL);
|
||||
|
||||
/* Determine the entry length */
|
||||
error = bhnd_nvram_btxt_entry_len(btxt->data, io_offset, &line_len,
|
||||
&env_len);
|
||||
if (error) {
|
||||
BHND_NV_LOG("unexpected error in entry_len(): %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Fetch the entry's value pointer and length */
|
||||
error = bhnd_nvram_io_read_ptr(btxt->data, io_offset, &eptr, env_len,
|
||||
NULL);
|
||||
if (error) {
|
||||
BHND_NV_LOG("unexpected error in read_ptr(): %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
error = bhnd_nvram_parse_env(eptr, env_len, '\0', NULL, NULL, &vptr,
|
||||
len);
|
||||
if (error) {
|
||||
BHND_NV_LOG("unexpected error in parse_env(): %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Type is always CSTR */
|
||||
*type = BHND_NVRAM_TYPE_STRING;
|
||||
|
||||
return (vptr);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_btxt_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
|
||||
{
|
||||
struct bhnd_nvram_btxt *btxt;
|
||||
const void *ptr;
|
||||
size_t io_offset, io_size;
|
||||
int error;
|
||||
|
||||
btxt = (struct bhnd_nvram_btxt *)nv;
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(btxt->data);
|
||||
io_offset = bhnd_nvram_btxt_io_offset(btxt, cookiep);
|
||||
|
||||
/* At EOF? */
|
||||
if (io_offset == io_size)
|
||||
BHND_NV_PANIC("invalid cookiep: %p", cookiep);
|
||||
|
||||
/* Variable name is found directly at the given offset; trailing
|
||||
* NUL means we can assume that it's at least 1 byte long */
|
||||
error = bhnd_nvram_io_read_ptr(btxt->data, io_offset, &ptr, 1, NULL);
|
||||
if (error)
|
||||
BHND_NV_PANIC("unexpected error in read_ptr(): %d\n", error);
|
||||
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
/* Convert cookie back to an I/O offset */
|
||||
static size_t
|
||||
bhnd_nvram_btxt_io_offset(struct bhnd_nvram_btxt *btxt, void *cookiep)
|
||||
{
|
||||
size_t io_size;
|
||||
uintptr_t cval;
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(btxt->data);
|
||||
cval = (uintptr_t)cookiep;
|
||||
|
||||
BHND_NV_ASSERT(cval < SIZE_MAX, ("cookie > SIZE_MAX)"));
|
||||
BHND_NV_ASSERT(cval <= io_size, ("cookie > io_size)"));
|
||||
|
||||
return ((size_t)cval);
|
||||
}
|
||||
|
||||
/* Determine the entry length and env 'key=value' string length of the entry
|
||||
* at @p offset */
|
||||
static int
|
||||
bhnd_nvram_btxt_entry_len(struct bhnd_nvram_io *io, size_t offset,
|
||||
size_t *line_len, size_t *env_len)
|
||||
{
|
||||
const uint8_t *baseptr, *p;
|
||||
const void *rbuf;
|
||||
size_t nbytes;
|
||||
int error;
|
||||
|
||||
/* Fetch read buffer */
|
||||
if ((error = bhnd_nvram_io_read_ptr(io, offset, &rbuf, 0, &nbytes)))
|
||||
return (error);
|
||||
|
||||
/* Find record termination (EOL, or '#') */
|
||||
p = rbuf;
|
||||
baseptr = rbuf;
|
||||
while ((size_t)(p - baseptr) < nbytes) {
|
||||
if (*p == '#' || *p == '\n' || *p == '\r')
|
||||
break;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
/* Got line length, now trim any trailing whitespace to determine
|
||||
* actual env length */
|
||||
*line_len = p - baseptr;
|
||||
*env_len = *line_len;
|
||||
|
||||
for (size_t i = 0; i < *line_len; i++) {
|
||||
char c = baseptr[*line_len - i - 1];
|
||||
if (!bhnd_nv_isspace(c))
|
||||
break;
|
||||
|
||||
*env_len -= 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Seek past the next line ending (\r, \r\n, or \n) */
|
||||
static int
|
||||
bhnd_nvram_btxt_seek_eol(struct bhnd_nvram_io *io, size_t *offset)
|
||||
{
|
||||
const uint8_t *baseptr, *p;
|
||||
const void *rbuf;
|
||||
size_t nbytes;
|
||||
int error;
|
||||
|
||||
/* Fetch read buffer */
|
||||
if ((error = bhnd_nvram_io_read_ptr(io, *offset, &rbuf, 0, &nbytes)))
|
||||
return (error);
|
||||
|
||||
baseptr = rbuf;
|
||||
p = rbuf;
|
||||
while ((size_t)(p - baseptr) < nbytes) {
|
||||
char c = *p;
|
||||
|
||||
/* Advance to next char. The next position may be EOF, in which
|
||||
* case a read will be invalid */
|
||||
p++;
|
||||
|
||||
if (c == '\r') {
|
||||
/* CR, check for optional LF */
|
||||
if ((size_t)(p - baseptr) < nbytes) {
|
||||
if (*p == '\n')
|
||||
p++;
|
||||
}
|
||||
|
||||
break;
|
||||
} else if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hit newline or EOF */
|
||||
*offset += (p - baseptr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Seek to the next valid non-comment line (or EOF) */
|
||||
static int
|
||||
bhnd_nvram_btxt_seek_next(struct bhnd_nvram_io *io, size_t *offset)
|
||||
{
|
||||
const uint8_t *baseptr, *p;
|
||||
const void *rbuf;
|
||||
size_t nbytes;
|
||||
int error;
|
||||
|
||||
/* Fetch read buffer */
|
||||
if ((error = bhnd_nvram_io_read_ptr(io, *offset, &rbuf, 0, &nbytes)))
|
||||
return (error);
|
||||
|
||||
/* Skip leading whitespace and comments */
|
||||
baseptr = rbuf;
|
||||
p = rbuf;
|
||||
while ((size_t)(p - baseptr) < nbytes) {
|
||||
char c = *p;
|
||||
|
||||
/* Skip whitespace */
|
||||
if (bhnd_nv_isspace(c)) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip entire comment line */
|
||||
if (c == '#') {
|
||||
size_t line_off = *offset + (p - baseptr);
|
||||
|
||||
if ((error = bhnd_nvram_btxt_seek_eol(io, &line_off)))
|
||||
return (error);
|
||||
|
||||
p = baseptr + (line_off - *offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Non-whitespace, non-comment */
|
||||
break;
|
||||
}
|
||||
|
||||
*offset += (p - baseptr);
|
||||
return (0);
|
||||
}
|
1988
sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
Normal file
1988
sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
Normal file
File diff suppressed because it is too large
Load Diff
150
sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
Normal file
150
sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_SPROMVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_SPROMVAR_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/bitstring.h>
|
||||
#else
|
||||
#include <bitstring.h>
|
||||
#endif
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
/** The maximum number of array elements encoded in a single SPROM variable */
|
||||
#define SPROM_ARRAY_MAXLEN 12
|
||||
|
||||
/**
|
||||
* SPROM opcode per-bind evaluation state.
|
||||
*/
|
||||
struct sprom_opcode_bind {
|
||||
uint8_t count;
|
||||
uint32_t skip_in; /**< input element skips */
|
||||
bool skip_in_negative; /**< skip_in should be subtracted */
|
||||
uint32_t skip_out; /**< output element skip */
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM opcode per-variable evaluation state.
|
||||
*/
|
||||
struct sprom_opcode_var {
|
||||
uint8_t nelem; /**< variable array length */
|
||||
uint32_t mask; /**< current bind input mask */
|
||||
int8_t shift; /**< current bind input shift */
|
||||
bhnd_nvram_type base_type; /**< current bind input type */
|
||||
uint32_t scale; /**< current scale to apply to scaled encodings */
|
||||
struct sprom_opcode_bind bind; /**< current bind state */
|
||||
bool have_bind; /**< if bind state is defined */
|
||||
size_t bind_total; /**< total count of bind operations performed */
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM opcode variable definition states.
|
||||
*
|
||||
* Ordered to support inequality comparisons
|
||||
* (e.g. >= SPROM_OPCODE_VAR_STATE_OPEN)
|
||||
*/
|
||||
typedef enum {
|
||||
SPROM_OPCODE_VAR_STATE_NONE = 1, /**< no variable entry available */
|
||||
SPROM_OPCODE_VAR_STATE_OPEN = 2, /**< currently parsing a variable entry */
|
||||
SPROM_OPCODE_VAR_STATE_DONE = 3 /**< full variable entry has been parsed */
|
||||
} sprom_opcode_var_state;
|
||||
|
||||
/**
|
||||
* SPROM opcode evaluation state
|
||||
*/
|
||||
struct sprom_opcode_state {
|
||||
const struct bhnd_sprom_layout *layout; /**< SPROM layout */
|
||||
|
||||
/** Current SPROM revision range */
|
||||
bitstr_t bit_decl(revs, SPROM_OP_REV_MAX);
|
||||
|
||||
const uint8_t *input; /**< opcode input position */
|
||||
|
||||
/* State preserved across variable definitions */
|
||||
uint32_t offset; /**< SPROM offset */
|
||||
size_t vid; /**< Variable ID */
|
||||
|
||||
/* State reset after end of each variable definition */
|
||||
struct sprom_opcode_var var; /**< variable record (if any) */
|
||||
sprom_opcode_var_state var_state; /**< variable record state */
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM opcode variable index entry
|
||||
*/
|
||||
struct sprom_opcode_idx {
|
||||
uint16_t vid; /**< SPROM variable ID */
|
||||
uint16_t offset; /**< SPROM input offset */
|
||||
uint16_t opcodes; /**< SPROM opcode offset */
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM value storage.
|
||||
*
|
||||
* Sufficient for representing the native encoding of any defined SPROM
|
||||
* variable.
|
||||
*/
|
||||
union bhnd_nvram_sprom_storage {
|
||||
uint8_t u8[SPROM_ARRAY_MAXLEN];
|
||||
uint16_t u16[SPROM_ARRAY_MAXLEN];
|
||||
uint32_t u32[SPROM_ARRAY_MAXLEN];
|
||||
int8_t i8[SPROM_ARRAY_MAXLEN];
|
||||
int16_t i16[SPROM_ARRAY_MAXLEN];
|
||||
int32_t i32[SPROM_ARRAY_MAXLEN];
|
||||
char ch[SPROM_ARRAY_MAXLEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM common integer value representation.
|
||||
*/
|
||||
union bhnd_nvram_sprom_intv {
|
||||
uint32_t u32;
|
||||
int32_t s32;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM data class instance state.
|
||||
*/
|
||||
struct bhnd_nvram_sprom {
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
struct bhnd_nvram_io *data; /**< backing SPROM image */
|
||||
const struct bhnd_sprom_layout *layout; /**< layout definition */
|
||||
struct sprom_opcode_state state; /**< opcode eval state */
|
||||
struct sprom_opcode_idx *idx; /**< opcode index entries */
|
||||
size_t num_idx; /**< opcode index entry count */
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_SPROMVAR_H_ */
|
662
sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
Normal file
662
sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
Normal file
@ -0,0 +1,662 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
|
||||
#include "bhnd_nvram_data_tlvreg.h"
|
||||
|
||||
/*
|
||||
* CFE TLV NVRAM data class.
|
||||
*
|
||||
* The CFE-defined TLV NVRAM format is used on the WGT634U.
|
||||
*/
|
||||
|
||||
struct bhnd_nvram_tlv {
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
struct bhnd_nvram_io *data; /**< backing buffer */
|
||||
size_t count; /**< variable count */
|
||||
};
|
||||
|
||||
BHND_NVRAM_DATA_CLASS_DEFN(tlv, "WGT634U", sizeof(struct bhnd_nvram_tlv))
|
||||
|
||||
/** Minimal TLV_ENV record header */
|
||||
struct bhnd_nvram_tlv_env_hdr {
|
||||
uint8_t tag;
|
||||
uint8_t size;
|
||||
} __packed;
|
||||
|
||||
/** Minimal TLV_ENV record */
|
||||
struct bhnd_nvram_tlv_env {
|
||||
struct bhnd_nvram_tlv_env_hdr hdr;
|
||||
uint8_t flags;
|
||||
char envp[];
|
||||
} __packed;
|
||||
|
||||
/* Return the length in bytes of an TLV_ENV's envp data */
|
||||
#define NVRAM_TLV_ENVP_DATA_LEN(_env) \
|
||||
(((_env)->hdr.size < sizeof((_env)->flags)) ? 0 : \
|
||||
((_env)->hdr.size - sizeof((_env)->flags)))
|
||||
|
||||
|
||||
static int bhnd_nvram_tlv_parse_size(
|
||||
struct bhnd_nvram_io *io,
|
||||
size_t *size);
|
||||
|
||||
static int bhnd_nvram_tlv_next_record(
|
||||
struct bhnd_nvram_io *io,
|
||||
size_t *next, size_t *offset,
|
||||
uint8_t *tag);
|
||||
|
||||
static struct bhnd_nvram_tlv_env *bhnd_nvram_tlv_next_env(
|
||||
struct bhnd_nvram_tlv *tlv,
|
||||
size_t *next, void **cookiep);
|
||||
|
||||
static struct bhnd_nvram_tlv_env *bhnd_nvram_tlv_get_env(
|
||||
struct bhnd_nvram_tlv *tlv,
|
||||
void *cookiep);
|
||||
|
||||
static void *bhnd_nvram_tlv_to_cookie(
|
||||
struct bhnd_nvram_tlv *tlv,
|
||||
size_t io_offset);
|
||||
static size_t bhnd_nvram_tlv_to_offset(
|
||||
struct bhnd_nvram_tlv *tlv,
|
||||
void *cookiep);
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_probe(struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_tlv_env ident;
|
||||
size_t nbytes;
|
||||
int error;
|
||||
|
||||
nbytes = bhnd_nvram_io_getsize(io);
|
||||
|
||||
/* Handle what might be an empty TLV image */
|
||||
if (nbytes < sizeof(ident)) {
|
||||
uint8_t tag;
|
||||
|
||||
/* Fetch just the first tag */
|
||||
error = bhnd_nvram_io_read(io, 0x0, &tag, sizeof(tag));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* This *could* be an empty TLV image, but all we're
|
||||
* testing for here is a single 0x0 byte followed by EOF */
|
||||
if (tag == NVRAM_TLV_TYPE_END)
|
||||
return (BHND_NVRAM_DATA_PROBE_MAYBE);
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Otherwise, look at the initial header for a valid TLV ENV tag,
|
||||
* plus one byte of the entry data */
|
||||
error = bhnd_nvram_io_read(io, 0x0, &ident,
|
||||
sizeof(ident) + sizeof(ident.envp[0]));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* First entry should be a variable record (which we statically
|
||||
* assert as being defined to use a single byte size field) */
|
||||
if (ident.hdr.tag != NVRAM_TLV_TYPE_ENV)
|
||||
return (ENXIO);
|
||||
|
||||
_Static_assert(NVRAM_TLV_TYPE_ENV & NVRAM_TLV_TF_U8_LEN,
|
||||
"TYPE_ENV is not a U8-sized field");
|
||||
|
||||
/* The entry must be at least 3 characters ('x=\0') in length */
|
||||
if (ident.hdr.size < 3)
|
||||
return (ENXIO);
|
||||
|
||||
/* The first character should be a valid key char (alpha) */
|
||||
if (!bhnd_nv_isalpha(ident.envp[0]))
|
||||
return (ENXIO);
|
||||
|
||||
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize @p tlv with the provided NVRAM TLV data mapped by @p src.
|
||||
*
|
||||
* @param tlv A newly allocated data instance.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_tlv_init(struct bhnd_nvram_tlv *tlv, struct bhnd_nvram_io *src)
|
||||
{
|
||||
struct bhnd_nvram_tlv_env *env;
|
||||
size_t size;
|
||||
size_t next;
|
||||
int error;
|
||||
|
||||
BHND_NV_ASSERT(tlv->data == NULL, ("tlv data already initialized"));
|
||||
|
||||
/* Determine the actual size of the TLV source data */
|
||||
if ((error = bhnd_nvram_tlv_parse_size(src, &size)))
|
||||
return (error);
|
||||
|
||||
/* Copy to our own internal buffer */
|
||||
if ((tlv->data = bhnd_nvram_iobuf_copy_range(src, 0x0, size)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Initialize our backing buffer */
|
||||
tlv->count = 0;
|
||||
next = 0;
|
||||
while ((env = bhnd_nvram_tlv_next_env(tlv, &next, NULL)) != NULL) {
|
||||
size_t env_len;
|
||||
size_t name_len;
|
||||
|
||||
/* TLV_ENV data must not be empty */
|
||||
env_len = NVRAM_TLV_ENVP_DATA_LEN(env);
|
||||
if (env_len == 0) {
|
||||
BHND_NV_LOG("cannot parse zero-length TLV_ENV record "
|
||||
"data\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Parse the key=value string, and then replace the '='
|
||||
* delimiter with '\0' to allow us to provide direct
|
||||
* name pointers from our backing buffer */
|
||||
error = bhnd_nvram_parse_env(env->envp, env_len, '=', NULL,
|
||||
&name_len, NULL, NULL);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error parsing TLV_ENV data: %d\n", error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Replace '=' with '\0' */
|
||||
*(env->envp + name_len) = '\0';
|
||||
|
||||
/* Add to variable count */
|
||||
tlv->count++;
|
||||
};
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
|
||||
{
|
||||
|
||||
struct bhnd_nvram_tlv *tlv;
|
||||
int error;
|
||||
|
||||
/* Allocate and initialize the TLV data instance */
|
||||
tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
|
||||
/* Parse the TLV input data and initialize our backing
|
||||
* data representation */
|
||||
if ((error = bhnd_nvram_tlv_init(tlv, io))) {
|
||||
bhnd_nvram_tlv_free(nv);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
bhnd_nvram_tlv_free(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
if (tlv->data != NULL)
|
||||
bhnd_nvram_io_free(tlv->data);
|
||||
}
|
||||
|
||||
size_t
|
||||
bhnd_nvram_tlv_count(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
return (tlv->count);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_size(struct bhnd_nvram_data *nv, size_t *size)
|
||||
{
|
||||
/* Let the serialization implementation calculate the length */
|
||||
return (bhnd_nvram_data_serialize(nv, NULL, size));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv;
|
||||
size_t limit;
|
||||
size_t next;
|
||||
uint8_t tag;
|
||||
int error;
|
||||
|
||||
tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
|
||||
/* Save the buffer capacity */
|
||||
if (buf == NULL)
|
||||
limit = 0;
|
||||
else
|
||||
limit = *len;
|
||||
|
||||
/* Write all of our TLV records to the output buffer (or just
|
||||
* calculate the buffer size that would be required) */
|
||||
next = 0;
|
||||
do {
|
||||
struct bhnd_nvram_tlv_env *env;
|
||||
uint8_t *p;
|
||||
size_t name_len;
|
||||
size_t rec_offset, rec_size;
|
||||
|
||||
/* Parse the TLV record */
|
||||
error = bhnd_nvram_tlv_next_record(tlv->data, &next,
|
||||
&rec_offset, &tag);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
rec_size = next - rec_offset;
|
||||
|
||||
/* Calculate our output pointer */
|
||||
if (rec_offset > limit || limit - rec_offset < rec_size) {
|
||||
/* buffer is full; cannot write */
|
||||
p = NULL;
|
||||
} else {
|
||||
p = (uint8_t *)buf + rec_offset;
|
||||
}
|
||||
|
||||
/* If not writing, nothing further to do for this record */
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
/* Copy to the output buffer */
|
||||
error = bhnd_nvram_io_read(tlv->data, rec_offset, p, rec_size);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* All further processing is TLV_ENV-specific */
|
||||
if (tag != NVRAM_TLV_TYPE_ENV)
|
||||
continue;
|
||||
|
||||
/* Restore the original key=value format, rewriting '\0'
|
||||
* delimiter back to '=' */
|
||||
env = (struct bhnd_nvram_tlv_env *)p;
|
||||
name_len = strlen(env->envp); /* skip variable name */
|
||||
*(env->envp + name_len) = '='; /* set '=' */
|
||||
} while (tag != NVRAM_TLV_TYPE_END);
|
||||
|
||||
/* The 'next' offset should now point at EOF, and represents
|
||||
* the total length of the serialized output. */
|
||||
*len = next;
|
||||
|
||||
if (buf != NULL && limit < *len)
|
||||
return (ENOMEM);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
bhnd_nvram_tlv_caps(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_tlv_next(struct bhnd_nvram_data *nv, void **cookiep)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv;
|
||||
struct bhnd_nvram_tlv_env *env;
|
||||
size_t io_offset;
|
||||
|
||||
tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
|
||||
/* Seek past the TLV_ENV record referenced by cookiep */
|
||||
io_offset = bhnd_nvram_tlv_to_offset(tlv, *cookiep);
|
||||
if (bhnd_nvram_tlv_next_env(tlv, &io_offset, NULL) == NULL)
|
||||
BHND_NV_PANIC("invalid cookiep: %p\n", cookiep);
|
||||
|
||||
/* Fetch the next TLV_ENV record */
|
||||
if ((env = bhnd_nvram_tlv_next_env(tlv, &io_offset, cookiep)) == NULL) {
|
||||
/* No remaining ENV records */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Return the NUL terminated name */
|
||||
return (env->envp);
|
||||
}
|
||||
|
||||
static void *
|
||||
bhnd_nvram_tlv_find(struct bhnd_nvram_data *nv, const char *name)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_find(nv, name));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
|
||||
}
|
||||
|
||||
static const void *
|
||||
bhnd_nvram_tlv_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
size_t *len, bhnd_nvram_type *type)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv;
|
||||
struct bhnd_nvram_tlv_env *env;
|
||||
const char *val;
|
||||
int error;
|
||||
|
||||
tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
|
||||
/* Fetch pointer to the TLV_ENV record */
|
||||
if ((env = bhnd_nvram_tlv_get_env(tlv, cookiep)) == NULL)
|
||||
BHND_NV_PANIC("invalid cookiep: %p", cookiep);
|
||||
|
||||
/* Parse value pointer and length from key\0value data */
|
||||
error = bhnd_nvram_parse_env(env->envp, NVRAM_TLV_ENVP_DATA_LEN(env),
|
||||
'\0', NULL, NULL, &val, len);
|
||||
if (error)
|
||||
BHND_NV_PANIC("unexpected error parsing '%s'", env->envp);
|
||||
|
||||
/* Type is always CSTR */
|
||||
*type = BHND_NVRAM_TYPE_STRING;
|
||||
|
||||
return (val);
|
||||
}
|
||||
|
||||
static const char *
|
||||
bhnd_nvram_tlv_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv;
|
||||
const struct bhnd_nvram_tlv_env *env;
|
||||
|
||||
tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
|
||||
/* Fetch pointer to the TLV_ENV record */
|
||||
if ((env = bhnd_nvram_tlv_get_env(tlv, cookiep)) == NULL)
|
||||
BHND_NV_PANIC("invalid cookiep: %p", cookiep);
|
||||
|
||||
/* Return name pointer */
|
||||
return (&env->envp[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the records starting at @p next, returning the parsed
|
||||
* record's @p tag, @p size, and @p offset.
|
||||
*
|
||||
* @param io The I/O context to parse.
|
||||
* @param[in,out] next The next offset to be parsed, or 0x0
|
||||
* to begin parsing. Upon successful
|
||||
* return, will be set to the offset of the
|
||||
* next record (or EOF, if
|
||||
* NVRAM_TLV_TYPE_END was parsed).
|
||||
* @param[out] offset The record's value offset.
|
||||
* @param[out] tag The record's tag.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL if parsing @p io as TLV fails.
|
||||
* @retval non-zero if reading @p io otherwise fails, a regular unix error
|
||||
* code will be returned.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_tlv_next_record(struct bhnd_nvram_io *io, size_t *next, size_t
|
||||
*offset, uint8_t *tag)
|
||||
{
|
||||
size_t io_offset, io_size;
|
||||
uint16_t parsed_len;
|
||||
uint8_t len_hdr[2];
|
||||
int error;
|
||||
|
||||
io_offset = *next;
|
||||
io_size = bhnd_nvram_io_getsize(io);
|
||||
|
||||
/* Save the record offset */
|
||||
if (offset != NULL)
|
||||
*offset = io_offset;
|
||||
|
||||
/* Fetch initial tag */
|
||||
error = bhnd_nvram_io_read(io, io_offset, tag, sizeof(*tag));
|
||||
if (error)
|
||||
return (error);
|
||||
io_offset++;
|
||||
|
||||
/* EOF */
|
||||
if (*tag == NVRAM_TLV_TYPE_END) {
|
||||
*next = io_offset;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read length field */
|
||||
if (*tag & NVRAM_TLV_TF_U8_LEN) {
|
||||
error = bhnd_nvram_io_read(io, io_offset, &len_hdr,
|
||||
sizeof(len_hdr[0]));
|
||||
if (error) {
|
||||
BHND_NV_LOG("error reading TLV record size: %d\n",
|
||||
error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
parsed_len = len_hdr[0];
|
||||
io_offset++;
|
||||
} else {
|
||||
error = bhnd_nvram_io_read(io, io_offset, &len_hdr,
|
||||
sizeof(len_hdr));
|
||||
if (error) {
|
||||
BHND_NV_LOG("error reading 16-bit TLV record "
|
||||
"size: %d\n", error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
parsed_len = (len_hdr[0] << 8) | len_hdr[1];
|
||||
io_offset += 2;
|
||||
}
|
||||
|
||||
/* Advance to next record */
|
||||
if (parsed_len > io_size || io_size - parsed_len < io_offset) {
|
||||
/* Hit early EOF */
|
||||
BHND_NV_LOG("TLV record length %hu truncated by input "
|
||||
"size of %zu\n", parsed_len, io_size);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
*next = io_offset + parsed_len;
|
||||
|
||||
/* Valid record found */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the TLV data in @p io to determine the total size of the TLV
|
||||
* data mapped by @p io (which may be less than the size of @p io).
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_tlv_parse_size(struct bhnd_nvram_io *io, size_t *size)
|
||||
{
|
||||
size_t next;
|
||||
uint8_t tag;
|
||||
int error;
|
||||
|
||||
/* We have to perform a minimal parse to determine the actual length */
|
||||
next = 0x0;
|
||||
*size = 0x0;
|
||||
|
||||
/* Iterate over the input until we hit END tag or the read fails */
|
||||
do {
|
||||
error = bhnd_nvram_tlv_next_record(io, &next, NULL, &tag);
|
||||
if (error)
|
||||
return (error);
|
||||
} while (tag != NVRAM_TLV_TYPE_END);
|
||||
|
||||
/* Offset should now point to EOF */
|
||||
BHND_NV_ASSERT(next <= bhnd_nvram_io_getsize(io),
|
||||
("parse returned invalid EOF offset"));
|
||||
|
||||
*size = next;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the records in @p tlv, returning a pointer to the next
|
||||
* NVRAM_TLV_TYPE_ENV record, or NULL if EOF is reached.
|
||||
*
|
||||
* @param tlv The TLV instance.
|
||||
* @param[in,out] next The next offset to be parsed, or 0x0
|
||||
* to begin parsing. Upon successful
|
||||
* return, will be set to the offset of the
|
||||
* next record.
|
||||
*/
|
||||
static struct bhnd_nvram_tlv_env *
|
||||
bhnd_nvram_tlv_next_env(struct bhnd_nvram_tlv *tlv, size_t *next,
|
||||
void **cookiep)
|
||||
{
|
||||
uint8_t tag;
|
||||
int error;
|
||||
|
||||
/* Find the next TLV_ENV record, starting at @p next */
|
||||
do {
|
||||
void *c;
|
||||
size_t offset;
|
||||
|
||||
/* Fetch the next TLV record */
|
||||
error = bhnd_nvram_tlv_next_record(tlv->data, next, &offset,
|
||||
&tag);
|
||||
if (error) {
|
||||
BHND_NV_LOG("unexpected error in next_record(): %d\n",
|
||||
error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Only interested in ENV records */
|
||||
if (tag != NVRAM_TLV_TYPE_ENV)
|
||||
continue;
|
||||
|
||||
/* Map and return TLV_ENV record pointer */
|
||||
c = bhnd_nvram_tlv_to_cookie(tlv, offset);
|
||||
|
||||
/* Provide the cookiep value for the returned record */
|
||||
if (cookiep != NULL)
|
||||
*cookiep = c;
|
||||
|
||||
return (bhnd_nvram_tlv_get_env(tlv, c));
|
||||
} while (tag != NVRAM_TLV_TYPE_END);
|
||||
|
||||
/* No remaining ENV records */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to the TLV_ENV record for @p cookiep, or NULL
|
||||
* if none vailable.
|
||||
*/
|
||||
static struct bhnd_nvram_tlv_env *
|
||||
bhnd_nvram_tlv_get_env(struct bhnd_nvram_tlv *tlv, void *cookiep)
|
||||
{
|
||||
struct bhnd_nvram_tlv_env *env;
|
||||
void *ptr;
|
||||
size_t navail;
|
||||
size_t io_offset, io_size;
|
||||
int error;
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(tlv->data);
|
||||
io_offset = bhnd_nvram_tlv_to_offset(tlv, cookiep);
|
||||
|
||||
/* At EOF? */
|
||||
if (io_offset == io_size)
|
||||
return (NULL);
|
||||
|
||||
/* Fetch non-const pointer to the record entry */
|
||||
error = bhnd_nvram_io_write_ptr(tlv->data, io_offset, &ptr,
|
||||
sizeof(env->hdr), &navail);
|
||||
if (error) {
|
||||
/* Should never occur with a valid cookiep */
|
||||
BHND_NV_LOG("error mapping record for cookiep: %d\n", error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Validate the record pointer */
|
||||
env = ptr;
|
||||
if (env->hdr.tag != NVRAM_TLV_TYPE_ENV) {
|
||||
/* Should never occur with a valid cookiep */
|
||||
BHND_NV_LOG("non-ENV record mapped for %p\n", cookiep);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Is the required variable name data is mapped? */
|
||||
if (navail < sizeof(struct bhnd_nvram_tlv_env_hdr) + env->hdr.size ||
|
||||
env->hdr.size == sizeof(env->flags))
|
||||
{
|
||||
/* Should never occur with a valid cookiep */
|
||||
BHND_NV_LOG("TLV_ENV variable data not mapped for %p\n",
|
||||
cookiep);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a cookiep for the given I/O offset.
|
||||
*/
|
||||
static void *
|
||||
bhnd_nvram_tlv_to_cookie(struct bhnd_nvram_tlv *tlv, size_t io_offset)
|
||||
{
|
||||
BHND_NV_ASSERT(io_offset < bhnd_nvram_io_getsize(tlv->data),
|
||||
("io_offset %zu out-of-range", io_offset));
|
||||
BHND_NV_ASSERT(io_offset < UINTPTR_MAX,
|
||||
("io_offset %#zx exceeds UINTPTR_MAX", io_offset));
|
||||
|
||||
return ((void *)(uintptr_t)(io_offset));
|
||||
}
|
||||
|
||||
/* Convert a cookiep back to an I/O offset */
|
||||
static size_t
|
||||
bhnd_nvram_tlv_to_offset(struct bhnd_nvram_tlv *tlv, void *cookiep)
|
||||
{
|
||||
size_t io_size;
|
||||
uintptr_t cval;
|
||||
|
||||
io_size = bhnd_nvram_io_getsize(tlv->data);
|
||||
cval = (uintptr_t)cookiep;
|
||||
|
||||
BHND_NV_ASSERT(cval < SIZE_MAX, ("cookie > SIZE_MAX)"));
|
||||
BHND_NV_ASSERT(cval <= io_size, ("cookie > io_size)"));
|
||||
|
||||
return ((size_t)cval);
|
||||
}
|
@ -29,47 +29,12 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_PARSERREG_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_PARSERREG_H_
|
||||
|
||||
|
||||
|
||||
#define NVRAM_GET_BITS(_value, _field) \
|
||||
((_value & _field ## _MASK) >> _field ## _SHIFT)
|
||||
|
||||
/* NVRAM header fields */
|
||||
#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
|
||||
#define NVRAM_VERSION 1
|
||||
|
||||
#define NVRAM_CRC_SKIP 9 /* skip magic, size, and crc8 */
|
||||
|
||||
#define NVRAM_CFG0_CRC_MASK 0x000000FF
|
||||
#define NVRAM_CFG0_CRC_SHIFT 0
|
||||
#define NVRAM_CFG0_VER_MASK 0x0000FF00
|
||||
#define NVRAM_CFG0_VER_SHIFT 8
|
||||
#define NVRAM_CFG0_SDRAM_INIT_MASK 0xFFFF0000
|
||||
#define NVRAM_CFG0_SDRAM_INIT_SHIFT 16
|
||||
#define NVRAM_CFG0_SDRAM_INIT_VAR "sdram_init"
|
||||
#define NVRAM_CFG0_SDRAM_INIT_FMT "0x%04x"
|
||||
|
||||
#define NVRAM_CFG1_SDRAM_CFG_MASK 0x0000FFFF
|
||||
#define NVRAM_CFG1_SDRAM_CFG_SHIFT 0
|
||||
#define NVRAM_CFG1_SDRAM_CFG_VAR "sdram_config"
|
||||
#define NVRAM_CFG1_SDRAM_CFG_FMT "0x%04x"
|
||||
|
||||
#define NVRAM_CFG1_SDRAM_REFRESH_MASK 0xFFFF0000
|
||||
#define NVRAM_CFG1_SDRAM_REFRESH_SHIFT 16
|
||||
#define NVRAM_CFG1_SDRAM_REFRESH_VAR "sdram_refresh"
|
||||
#define NVRAM_CFG1_SDRAM_REFRESH_FMT "0x%04x"
|
||||
|
||||
#define NVRAM_SDRAM_NCDL_MASK UINT32_MAX
|
||||
#define NVRAM_SDRAM_NCDL_SHIFT 0
|
||||
#define NVRAM_SDRAM_NCDL_VAR "sdram_ncdl"
|
||||
#define NVRAM_SDRAM_NCDL_FMT "0x%08x"
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_TLVREG_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_TLVREG_H_
|
||||
|
||||
/* WGT634U-specific TLV encoding */
|
||||
#define NVRAM_TLV_TF_U8_LEN 0x01 /**< type has 8-bit length */
|
||||
#define NVRAM_TLV_TYPE_END 0x00 /**< end of table */
|
||||
#define NVRAM_TLV_TYPE_ENV 0x01 /**< variable record */
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_PARSERVAR_H_ */
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_TLVREG_H_ */
|
188
sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
Normal file
188
sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
Normal file
@ -0,0 +1,188 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_DATAVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_DATAVAR_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker_set.h>
|
||||
#include <sys/refcount.h>
|
||||
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
#include "bhnd_nvram_data.h"
|
||||
|
||||
/** Registered NVRAM parser class instances. */
|
||||
SET_DECLARE(bhnd_nvram_data_class_set, bhnd_nvram_data_class_t);
|
||||
|
||||
void *bhnd_nvram_data_generic_find(struct bhnd_nvram_data *nv,
|
||||
const char *name);
|
||||
int bhnd_nvram_data_generic_rp_getvar(struct bhnd_nvram_data *nv,
|
||||
void *cookiep, void *outp, size_t *olen, bhnd_nvram_type otype);
|
||||
|
||||
/** @see bhnd_nvram_data_class_desc() */
|
||||
typedef const char *(bhnd_nvram_data_op_class_desc)(void);
|
||||
|
||||
/** @see bhnd_nvram_data_probe() */
|
||||
typedef int (bhnd_nvram_data_op_probe)(struct bhnd_nvram_io *io);
|
||||
|
||||
/** @see bhnd_nvram_data_new() */
|
||||
typedef int (bhnd_nvram_data_op_new)(struct bhnd_nvram_data *nv,
|
||||
struct bhnd_nvram_io *io);
|
||||
|
||||
/** Free all resources associated with @p nv. Called by
|
||||
* bhnd_nvram_data_release() when the reference count reaches zero. */
|
||||
typedef void (bhnd_nvram_data_op_free)(struct bhnd_nvram_data *nv);
|
||||
|
||||
/** @see bhnd_nvram_data_count() */
|
||||
typedef size_t (bhnd_nvram_data_op_count)(struct bhnd_nvram_data *nv);
|
||||
|
||||
/** @see bhnd_nvram_data_size() */
|
||||
typedef int (bhnd_nvram_data_op_size)(struct bhnd_nvram_data *nv,
|
||||
size_t *len);
|
||||
|
||||
/** @see bhnd_nvram_data_serialize() */
|
||||
typedef int (bhnd_nvram_data_op_serialize)(
|
||||
struct bhnd_nvram_data *nv, void *buf,
|
||||
size_t *len);
|
||||
|
||||
/** @see bhnd_nvram_data_caps() */
|
||||
typedef uint32_t (bhnd_nvram_data_op_caps)(struct bhnd_nvram_data *nv);
|
||||
|
||||
/** @see bhnd_nvram_data_next() */
|
||||
typedef const char *(bhnd_nvram_data_op_next)(struct bhnd_nvram_data *nv,
|
||||
void **cookiep);
|
||||
|
||||
/** @see bhnd_nvram_data_find() */
|
||||
typedef void *(bhnd_nvram_data_op_find)(struct bhnd_nvram_data *nv,
|
||||
const char *name);
|
||||
|
||||
/** @see bhnd_nvram_data_getvar_name() */
|
||||
typedef const char *(bhnd_nvram_data_op_getvar_name)(
|
||||
struct bhnd_nvram_data *nv, void *cookiep);
|
||||
|
||||
/** @see bhnd_nvram_data_getvar() */
|
||||
typedef int (bhnd_nvram_data_op_getvar)(struct bhnd_nvram_data *nv,
|
||||
void *cookiep, void *buf, size_t *len,
|
||||
bhnd_nvram_type type);
|
||||
|
||||
/** @see bhnd_nvram_data_getvar_ptr() */
|
||||
typedef const void *(bhnd_nvram_data_op_getvar_ptr)(
|
||||
struct bhnd_nvram_data *nv, void *cookiep,
|
||||
size_t *len, bhnd_nvram_type *type);
|
||||
|
||||
/**
|
||||
* NVRAM data class.
|
||||
*/
|
||||
struct bhnd_nvram_data_class {
|
||||
const char *desc; /**< description */
|
||||
size_t size; /**< instance size */
|
||||
bhnd_nvram_data_op_probe *op_probe;
|
||||
bhnd_nvram_data_op_new *op_new;
|
||||
bhnd_nvram_data_op_free *op_free;
|
||||
bhnd_nvram_data_op_count *op_count;
|
||||
bhnd_nvram_data_op_size *op_size;
|
||||
bhnd_nvram_data_op_serialize *op_serialize;
|
||||
bhnd_nvram_data_op_caps *op_caps;
|
||||
bhnd_nvram_data_op_next *op_next;
|
||||
bhnd_nvram_data_op_find *op_find;
|
||||
bhnd_nvram_data_op_getvar *op_getvar;
|
||||
bhnd_nvram_data_op_getvar_ptr *op_getvar_ptr;
|
||||
bhnd_nvram_data_op_getvar_name *op_getvar_name;
|
||||
};
|
||||
|
||||
/**
|
||||
* NVRAM data instance.
|
||||
*/
|
||||
struct bhnd_nvram_data {
|
||||
struct bhnd_nvram_data_class *cls;
|
||||
volatile u_int refs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper macro for BHND_NVRAM_DATA_CLASS_DEFN().
|
||||
*
|
||||
* Declares a bhnd_nvram_data_class method implementation with class name
|
||||
* _cname and method name _mname
|
||||
*/
|
||||
#define BHND_NVRAM_DATA_CLASS_DECL_METHOD(_cname, _mname) \
|
||||
static bhnd_nvram_data_op_ ## _mname \
|
||||
bhnd_nvram_ ## _cname ## _ ## _mname; \
|
||||
|
||||
/*
|
||||
* Helper macro for BHND_NVRAM_DATA_CLASS_DEFN().
|
||||
*
|
||||
* Assign a bhnd_nvram_data_class method implementation with class name
|
||||
* @p _cname and method name @p _mname
|
||||
*/
|
||||
#define BHND_NVRAM_DATA_CLASS_ASSIGN_METHOD(_cname, _mname) \
|
||||
.op_ ## _mname = bhnd_nvram_ ## _cname ## _ ## _mname,
|
||||
|
||||
/*
|
||||
* Helper macro for BHND_NVRAM_DATA_CLASS_DEFN().
|
||||
*
|
||||
* Iterate over all bhnd_nvram_data_class method names, calling
|
||||
* _macro with the class name _cname as the first argument, and
|
||||
* a bhnd_nvram_data_class method name as the second.
|
||||
*/
|
||||
#define BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, _macro) \
|
||||
_macro(_cname, probe) \
|
||||
_macro(_cname, new) \
|
||||
_macro(_cname, free) \
|
||||
_macro(_cname, count) \
|
||||
_macro(_cname, size) \
|
||||
_macro(_cname, serialize) \
|
||||
_macro(_cname, caps) \
|
||||
_macro(_cname, next) \
|
||||
_macro(_cname, find) \
|
||||
_macro(_cname, getvar) \
|
||||
_macro(_cname, getvar_ptr) \
|
||||
_macro(_cname, getvar_name)
|
||||
|
||||
/**
|
||||
* Define a bhnd_nvram_data_class with class name @p _n and description
|
||||
* @p _desc, and register with bhnd_nvram_data_class_set.
|
||||
*/
|
||||
#define BHND_NVRAM_DATA_CLASS_DEFN(_cname, _desc, _size) \
|
||||
BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, \
|
||||
BHND_NVRAM_DATA_CLASS_DECL_METHOD) \
|
||||
\
|
||||
struct bhnd_nvram_data_class bhnd_nvram_## _cname ## _class = { \
|
||||
.desc = (_desc), \
|
||||
.size = (_size), \
|
||||
BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, \
|
||||
BHND_NVRAM_DATA_CLASS_ASSIGN_METHOD) \
|
||||
}; \
|
||||
\
|
||||
DATA_SET(bhnd_nvram_data_class_set, \
|
||||
bhnd_nvram_## _cname ## _class);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_DATAVAR_H_ */
|
205
sys/dev/bhnd/nvram/bhnd_nvram_io.c
Normal file
205
sys/dev/bhnd/nvram/bhnd_nvram_io.c
Normal file
@ -0,0 +1,205 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_io.h"
|
||||
#include "bhnd_nvram_iovar.h"
|
||||
|
||||
/**
|
||||
* Read exactly @p nbytes from @p io at @p offset.
|
||||
*
|
||||
* @param io NVRAM I/O context.
|
||||
* @param offset The offset within @p io at which to perform the read.
|
||||
* @param[out] buffer Output buffer to which @p nbytes from @p io will be
|
||||
* written.
|
||||
* @param nbytes The maximum number of bytes to be read from @p io.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EIO if an input error occured reading @p io.
|
||||
* @retval ENXIO if the request for @p offset or @p nbytes exceeds the size
|
||||
* of @p io.
|
||||
* @retval EFAULT if @p io requires I/O request alignment and @p offset is
|
||||
* misaligned.
|
||||
* @retval EFAULT if @p io requires I/O request alignment and @p nbytes is
|
||||
* misaligned and cannot be rounded down to an aligned non-zero value.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_io_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||
size_t nbytes)
|
||||
{
|
||||
return (io->iops->read(io, offset, buffer, nbytes));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to fetch a pointer to @p io's internal read buffer, if
|
||||
* supported by @p io.
|
||||
*
|
||||
* The returned pointer is only gauranteed to be valid until the next I/O
|
||||
* operation performed on @p io; concrete implementations of bhnd_nvram_io
|
||||
* may provide stronger gaurantees.
|
||||
*
|
||||
* @param io NVRAM I/O context.
|
||||
* @param offset The offset within @p io for which to return a buffer pointer.
|
||||
* @param[out] ptr On success, will be initialized with a pointer to @p io's
|
||||
* internal read buffer.
|
||||
* @param nbytes The minimum number of bytes that must be readable at @p offset.
|
||||
* @param[out] navail The actual number of readable bytes, which may be greater
|
||||
* than @p nbytes. If this value is not required, a NULL pointer may be
|
||||
* provided.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EIO if an input error occured reading @p io.
|
||||
* @retval ENODEV if @p io does not support direct access to its backing read
|
||||
* buffer.
|
||||
* @retval ENXIO if the request exceeds the size of @p io.
|
||||
* @retval EFAULT if @p io requires I/O request alignment and @p offset or
|
||||
* @p nbytes are misaligned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_io_read_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
const void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
return (io->iops->read_ptr(io, offset, ptr, nbytes, navail));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write @p nbytes to @p io at @p offset.
|
||||
*
|
||||
* @param io NVRAM I/O context.
|
||||
* @param offset The offset within @p io at which to perform the write.
|
||||
* @param buffer Data to be written to @p io.
|
||||
* @param nbytes The number of bytes to be written from @p buffer.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EIO if an output error occurs writing to @p io.
|
||||
* @retval ENODEV if @p io does not support writing.
|
||||
* @retval ENXIO if @p io does not support writes beyond the existing
|
||||
* end-of-file, and a write at @p offset would exceed the size of the @p io
|
||||
* backing data store.
|
||||
* @retval EFAULT if @p io requires I/O request alignment and @p offset or
|
||||
* @p nbytes are misaligned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_io_write(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||
size_t nbytes)
|
||||
{
|
||||
return (io->iops->write(io, offset, buffer, nbytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to fetch a writable pointer to @p io's internal write buffer, if
|
||||
* supported by @p io.
|
||||
*
|
||||
* The returned pointer is only gauranteed to be valid until the next I/O
|
||||
* operation performed on @p io; concrete implementations of bhnd_nvram_io
|
||||
* may provide stronger gaurantees.
|
||||
*
|
||||
* @param io NVRAM I/O context.
|
||||
* @param offset The offset within @p io for which to return a buffer pointer.
|
||||
* @param[in,out] ptr On success, will be initialized with a pointer to @p io's
|
||||
* internal buffer at which up to @p nbytes may be written.
|
||||
* @param nbytes The minimum number of bytes that must be writable at @p offset.
|
||||
* @param[out] navail The actual number of writable bytes, which may be greater
|
||||
* than @p nbytes. If this value is not required, a NULL pointer may be
|
||||
* provided.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EIO if an output error occurs preparing @p io's write buffer.
|
||||
* @retval ENODEV if @p io does not support direct access to its backing write
|
||||
* buffer.
|
||||
* @retval ENXIO if @p io does not support writes beyond the existing
|
||||
* end-of-file, and a write at @p offset of @p nbytes would exceed the size of
|
||||
* the @p io backing data store.
|
||||
* @retval EFAULT if @p io requires I/O request alignment and @p offset or
|
||||
* @p nbytes are misaligned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_io_write_ptr(struct bhnd_nvram_io *io, size_t offset, void **ptr,
|
||||
size_t nbytes, size_t *navail)
|
||||
{
|
||||
return (io->iops->write_ptr(io, offset, ptr, nbytes, navail));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of bytes readable via @p io.
|
||||
*
|
||||
* @param io NVRAM I/O context.
|
||||
*/
|
||||
size_t
|
||||
bhnd_nvram_io_getsize(struct bhnd_nvram_io *io)
|
||||
{
|
||||
return (io->iops->getsize(io));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to set the size of @p io to @p size.
|
||||
*
|
||||
* If the total size of @p io is increased, the contents of the newly mapped
|
||||
* bytes are undefined; concrete implementations of bhnd_nvram_io may
|
||||
* provide stronger gaurantees.
|
||||
*
|
||||
* @param io NVRAM I/O context.
|
||||
* @param size The new size.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EIO if an I/O error occurs resizing @p io.
|
||||
* @retval ENODEV if @p io does not support resizing.
|
||||
* @retval ENXIO if @p size exceeds the capacity or other limits of @p io.
|
||||
* @retval EFAULT if @p io requires I/O request alignment and @p size is
|
||||
* misaligned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_io_setsize(struct bhnd_nvram_io *io, size_t size)
|
||||
{
|
||||
return (io->iops->setsize(io, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a previously allocated I/O context, releasing all associated
|
||||
* resources.
|
||||
*
|
||||
* @param io The I/O context to be freed.
|
||||
*/
|
||||
void
|
||||
bhnd_nvram_io_free(struct bhnd_nvram_io *io)
|
||||
{
|
||||
return (io->iops->free(io));
|
||||
}
|
||||
|
79
sys/dev/bhnd/nvram/bhnd_nvram_io.h
Normal file
79
sys/dev/bhnd/nvram/bhnd_nvram_io.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_IO_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_IO_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
struct bhnd_nvram_io;
|
||||
|
||||
struct bhnd_nvram_io *bhnd_nvram_iobuf_new(const void *buffer, size_t size);
|
||||
struct bhnd_nvram_io *bhnd_nvram_iobuf_empty(size_t size, size_t capacity);
|
||||
struct bhnd_nvram_io *bhnd_nvram_iobuf_copy(struct bhnd_nvram_io *src);
|
||||
struct bhnd_nvram_io *bhnd_nvram_iobuf_copy_range(struct bhnd_nvram_io *src,
|
||||
size_t offset, size_t size);
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct bhnd_nvram_io *bhnd_nvram_iores_new(struct bhnd_resource *r,
|
||||
bus_size_t offset, bus_size_t size,
|
||||
u_int bus_width);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
size_t bhnd_nvram_io_getsize(struct bhnd_nvram_io *io);
|
||||
int bhnd_nvram_io_setsize(struct bhnd_nvram_io *io,
|
||||
size_t size);
|
||||
|
||||
int bhnd_nvram_io_read(struct bhnd_nvram_io *io,
|
||||
size_t offset, void *buffer, size_t nbytes);
|
||||
int bhnd_nvram_io_read_ptr(struct bhnd_nvram_io *io,
|
||||
size_t offset, const void **ptr, size_t nbytes,
|
||||
size_t *navail);
|
||||
|
||||
int bhnd_nvram_io_write(struct bhnd_nvram_io *io,
|
||||
size_t offset, void *buffer, size_t nbytes);
|
||||
int bhnd_nvram_io_write_ptr(struct bhnd_nvram_io *io,
|
||||
size_t offset, void **ptr, size_t nbytes,
|
||||
size_t *navail);
|
||||
|
||||
void bhnd_nvram_io_free(struct bhnd_nvram_io *io);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_IO_H_ */
|
341
sys/dev/bhnd/nvram/bhnd_nvram_iobuf.c
Normal file
341
sys/dev/bhnd/nvram/bhnd_nvram_iobuf.c
Normal file
@ -0,0 +1,341 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_io.h"
|
||||
#include "bhnd_nvram_iovar.h"
|
||||
|
||||
/**
|
||||
* Buffer-backed NVRAM I/O context.
|
||||
*
|
||||
* iobuf instances are gauranteed to provide persistent references to its
|
||||
* backing contigious buffer via bhnd_nvram_io_read_ptr() and
|
||||
* bhnd_nvram_io_write_ptr().
|
||||
*/
|
||||
struct bhnd_nvram_iobuf {
|
||||
struct bhnd_nvram_io io; /**< common I/O instance state */
|
||||
void *buf; /**< backing buffer. if inline-allocated, will
|
||||
be a reference to data[]. */
|
||||
size_t size; /**< size of @p buf */
|
||||
size_t capacity; /**< capacity of @p buf */
|
||||
uint8_t data[]; /**< inline buffer allocation */
|
||||
};
|
||||
|
||||
BHND_NVRAM_IOPS_DEFN(iobuf)
|
||||
|
||||
/**
|
||||
* Allocate and return a new I/O context with an uninitialized
|
||||
* buffer of @p size and @p capacity.
|
||||
*
|
||||
* The caller is responsible for deallocating the returned I/O context via
|
||||
* bhnd_nvram_io_free().
|
||||
*
|
||||
* If @p capacity is less than @p size, a capacity of @p size will be used.
|
||||
*
|
||||
* @param size The initial size of the I/O context.
|
||||
* @param capacity The total capacity of the I/O context buffer;
|
||||
* the returned I/O context may be resized up to
|
||||
* @p capacity via bhnd_nvram_io_setsize().
|
||||
*
|
||||
* @retval bhnd_nvram_iobuf success.
|
||||
* @retval NULL allocation failed.
|
||||
* @retval NULL the requested @p capacity is less than
|
||||
* @p size.
|
||||
*/
|
||||
struct bhnd_nvram_io *
|
||||
bhnd_nvram_iobuf_empty(size_t size, size_t capacity)
|
||||
{
|
||||
struct bhnd_nvram_iobuf *iobuf;
|
||||
size_t iosz;
|
||||
bool inline_alloc;
|
||||
|
||||
/* Sanity check the capacity */
|
||||
if (size > capacity)
|
||||
return (NULL);
|
||||
|
||||
/* Would sizeof(iobuf)+capacity overflow? */
|
||||
if (SIZE_MAX - sizeof(*iobuf) < capacity) {
|
||||
inline_alloc = false;
|
||||
iosz = sizeof(*iobuf);
|
||||
} else {
|
||||
inline_alloc = true;
|
||||
iosz = sizeof(*iobuf) + capacity;
|
||||
}
|
||||
|
||||
/* Allocate I/O context */
|
||||
iobuf = bhnd_nv_malloc(iosz);
|
||||
if (iobuf == NULL)
|
||||
return (NULL);
|
||||
|
||||
iobuf->io.iops = &bhnd_nvram_iobuf_ops;
|
||||
iobuf->buf = NULL;
|
||||
iobuf->size = size;
|
||||
iobuf->capacity = capacity;
|
||||
|
||||
/* Either allocate our backing buffer, or initialize the
|
||||
* backing buffer with a reference to our inline allocation. */
|
||||
if (inline_alloc)
|
||||
iobuf->buf = &iobuf->data;
|
||||
else
|
||||
iobuf->buf = bhnd_nv_malloc(iobuf->capacity);
|
||||
|
||||
|
||||
if (iobuf->buf == NULL) {
|
||||
bhnd_nv_free(iobuf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (&iobuf->io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and return a new I/O context, copying @p size from @p buffer.
|
||||
*
|
||||
* The caller is responsible for deallocating the returned I/O context via
|
||||
* bhnd_nvram_io_free().
|
||||
*
|
||||
* @param buffer The buffer data be copied by the returned I/O context.
|
||||
* @param size The size of @p buffer, in bytes.
|
||||
*
|
||||
* @retval bhnd_nvram_io success.
|
||||
* @retval NULL allocation failed.
|
||||
*/
|
||||
struct bhnd_nvram_io *
|
||||
bhnd_nvram_iobuf_new(const void *buffer, size_t size)
|
||||
{
|
||||
struct bhnd_nvram_io *io;
|
||||
struct bhnd_nvram_iobuf *iobuf;
|
||||
|
||||
/* Allocate the iobuf */
|
||||
if ((io = bhnd_nvram_iobuf_empty(size, size)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* Copy the input to our new iobuf instance */
|
||||
iobuf = (struct bhnd_nvram_iobuf *)io;
|
||||
memcpy(iobuf->buf, buffer, iobuf->size);
|
||||
|
||||
return (io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and return a new I/O context providing an in-memory copy
|
||||
* of the data mapped by @p src.
|
||||
*
|
||||
* The caller is responsible for deallocating the returned I/O context via
|
||||
* bhnd_nvram_io_free().
|
||||
*
|
||||
* @param src The I/O context to be copied.
|
||||
*
|
||||
* @retval bhnd_nvram_io success.
|
||||
* @retval NULL allocation failed.
|
||||
* @retval NULL copying @p src failed.
|
||||
*/
|
||||
struct bhnd_nvram_io *
|
||||
bhnd_nvram_iobuf_copy(struct bhnd_nvram_io *src)
|
||||
{
|
||||
return (bhnd_nvram_iobuf_copy_range(src, 0x0,
|
||||
bhnd_nvram_io_getsize(src)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and return a new I/O context providing an in-memory copy
|
||||
* of @p size bytes mapped at @p offset by @p src.
|
||||
*
|
||||
* The caller is responsible for deallocating the returned I/O context via
|
||||
* bhnd_nvram_io_free().
|
||||
*
|
||||
* @param src The I/O context to be copied.
|
||||
* @param offset The offset of the bytes to be copied from @p src.
|
||||
* @param size The number of bytes to copy at @p offset from @p src.
|
||||
*
|
||||
* @retval bhnd_nvram_io success.
|
||||
* @retval NULL allocation failed.
|
||||
* @retval NULL copying @p src failed.
|
||||
*/
|
||||
struct bhnd_nvram_io *
|
||||
bhnd_nvram_iobuf_copy_range(struct bhnd_nvram_io *src, size_t offset,
|
||||
size_t size)
|
||||
{
|
||||
struct bhnd_nvram_io *io;
|
||||
struct bhnd_nvram_iobuf *iobuf;
|
||||
int error;
|
||||
|
||||
/* Check if offset+size would overflow */
|
||||
if (SIZE_MAX - size < offset)
|
||||
return (NULL);
|
||||
|
||||
/* Allocate the iobuf instance */
|
||||
if ((io = bhnd_nvram_iobuf_empty(size, size)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* Copy the input I/O context */
|
||||
iobuf = (struct bhnd_nvram_iobuf *)io;
|
||||
if ((error = bhnd_nvram_io_read(src, offset, iobuf->buf, size))) {
|
||||
bhnd_nvram_io_free(&iobuf->io);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (io);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
bhnd_nvram_iobuf_free(struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_iobuf *iobuf = (struct bhnd_nvram_iobuf *)io;
|
||||
|
||||
/* Free the backing buffer if it wasn't allocated inline */
|
||||
if (iobuf->buf != &iobuf->data)
|
||||
bhnd_nv_free(iobuf->buf);
|
||||
|
||||
bhnd_nv_free(iobuf);
|
||||
}
|
||||
|
||||
static size_t
|
||||
bhnd_nvram_iobuf_getsize(struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_iobuf *iobuf = (struct bhnd_nvram_iobuf *)io;
|
||||
return (iobuf->size);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iobuf_setsize(struct bhnd_nvram_io *io, size_t size)
|
||||
{
|
||||
struct bhnd_nvram_iobuf *iobuf = (struct bhnd_nvram_iobuf *)io;
|
||||
|
||||
/* Can't exceed the actual capacity */
|
||||
if (size > iobuf->capacity)
|
||||
return (ENXIO);
|
||||
|
||||
iobuf->size = size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Common iobuf_(read|write)_ptr implementation */
|
||||
static int
|
||||
bhnd_nvram_iobuf_ptr(struct bhnd_nvram_iobuf *iobuf, size_t offset, void **ptr,
|
||||
size_t nbytes, size_t *navail)
|
||||
{
|
||||
size_t avail;
|
||||
|
||||
/* Verify offset+nbytes fall within the buffer range */
|
||||
if (offset > iobuf->size)
|
||||
return (ENXIO);
|
||||
|
||||
avail = iobuf->size - offset;
|
||||
if (avail < nbytes)
|
||||
return (ENXIO);
|
||||
|
||||
/* Valid I/O range, provide a pointer to the buffer and the
|
||||
* total count of available bytes */
|
||||
*ptr = ((uint8_t *)iobuf->buf) + offset;
|
||||
if (navail != NULL)
|
||||
*navail = avail;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iobuf_read_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
const void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
struct bhnd_nvram_iobuf *iobuf;
|
||||
void *ioptr;
|
||||
int error;
|
||||
|
||||
iobuf = (struct bhnd_nvram_iobuf *) io;
|
||||
|
||||
/* Return a pointer into our backing buffer */
|
||||
error = bhnd_nvram_iobuf_ptr(iobuf, offset, &ioptr, nbytes, navail);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
*ptr = ioptr;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iobuf_write_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
struct bhnd_nvram_iobuf *iobuf;
|
||||
|
||||
iobuf = (struct bhnd_nvram_iobuf *) io;
|
||||
|
||||
/* Return a pointer into our backing buffer */
|
||||
return (bhnd_nvram_iobuf_ptr(iobuf, offset, ptr, nbytes, navail));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iobuf_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||
size_t nbytes)
|
||||
{
|
||||
const void *ptr;
|
||||
int error;
|
||||
|
||||
/* Try to fetch a direct pointer for at least nbytes */
|
||||
if ((error = bhnd_nvram_io_read_ptr(io, offset, &ptr, nbytes, NULL)))
|
||||
return (error);
|
||||
|
||||
/* Copy out the requested data */
|
||||
memcpy(buffer, ptr, nbytes);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iobuf_write(struct bhnd_nvram_io *io, size_t offset,
|
||||
void *buffer, size_t nbytes)
|
||||
{
|
||||
void *ptr;
|
||||
int error;
|
||||
|
||||
/* Try to fetch a direct pointer for at least nbytes */
|
||||
if ((error = bhnd_nvram_io_write_ptr(io, offset, &ptr, nbytes, NULL)))
|
||||
return (error);
|
||||
|
||||
/* Copy in the provided data */
|
||||
memcpy(ptr, buffer, nbytes);
|
||||
return (0);
|
||||
}
|
302
sys/dev/bhnd/nvram/bhnd_nvram_iores.c
Normal file
302
sys/dev/bhnd/nvram/bhnd_nvram_iores.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
|
||||
#include "bhnd_nvram_io.h"
|
||||
#include "bhnd_nvram_iovar.h"
|
||||
|
||||
/**
|
||||
* BHND resource-backed NVRAM I/O context.
|
||||
*/
|
||||
struct bhnd_nvram_iores {
|
||||
struct bhnd_nvram_io io; /**< common I/O instance state */
|
||||
struct bhnd_resource *res; /**< backing resource (borrowed ref) */
|
||||
size_t offset; /**< offset within res */
|
||||
size_t size; /**< size relative to the base offset */
|
||||
u_int bus_width; /**< data type byte width to be used
|
||||
when performing bus operations
|
||||
on res. (1, 2, or 4 bytes) */
|
||||
};
|
||||
|
||||
BHND_NVRAM_IOPS_DEFN(iores);
|
||||
|
||||
/**
|
||||
* Allocate and return a new I/O context backed by a borrowed reference to @p r.
|
||||
*
|
||||
* The caller is responsible for deallocating the returned I/O context via
|
||||
* bhnd_nvram_io_free().
|
||||
*
|
||||
* @param r The resource to be mapped by the returned I/O
|
||||
* context.
|
||||
* @param offset Offset
|
||||
* @param bus_width The required I/O width (1, 2, or 4 bytes) to be
|
||||
* used when reading from @p r.
|
||||
*
|
||||
* @retval bhnd_nvram_io success.
|
||||
* @retval NULL if allocation fails, or an invalid argument
|
||||
* is supplied.
|
||||
*/
|
||||
struct bhnd_nvram_io *
|
||||
bhnd_nvram_iores_new(struct bhnd_resource *r, bus_size_t offset,
|
||||
bus_size_t size, u_int bus_width)
|
||||
{
|
||||
struct bhnd_nvram_iores *iores;
|
||||
rman_res_t r_start, r_size;
|
||||
|
||||
/* Verify the bus width */
|
||||
switch (bus_width) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
/* valid */
|
||||
break;
|
||||
default:
|
||||
BHND_NV_LOG("invalid bus width %u\n", bus_width);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* offset/size must not exceed our internal size_t representation,
|
||||
* or our bus_size_t usage (note that BUS_SPACE_MAXSIZE may be less
|
||||
* than 2^(sizeof(bus_size_t) * 32). */
|
||||
if (size > SIZE_MAX || offset > SIZE_MAX) {
|
||||
BHND_NV_LOG("offset %#jx+%#jx exceeds SIZE_MAX\n",
|
||||
(uintmax_t)offset, (uintmax_t)offset);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (size > BUS_SPACE_MAXSIZE || offset > BUS_SPACE_MAXSIZE)
|
||||
{
|
||||
BHND_NV_LOG("offset %#jx+%#jx exceeds BUS_SPACE_MAXSIZE\n",
|
||||
(uintmax_t)offset, (uintmax_t)offset);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* offset/size fall within the resource's mapped range */
|
||||
r_size = rman_get_size(r->res);
|
||||
r_start = rman_get_start(r->res);
|
||||
if (r_size < offset || r_size < size || r_size - size < offset)
|
||||
return (NULL);
|
||||
|
||||
/* offset/size must be bus_width aligned */
|
||||
if ((r_start + offset) % bus_width != 0) {
|
||||
BHND_NV_LOG("base address %#jx+%#jx not aligned to bus width "
|
||||
"%u\n", (uintmax_t)r_start, (uintmax_t)offset, bus_width);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (size % bus_width != 0) {
|
||||
BHND_NV_LOG("size %#jx not aligned to bus width %u\n",
|
||||
(uintmax_t)size, bus_width);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Allocate and return the I/O context */
|
||||
iores = malloc(sizeof(*iores), M_BHND_NVRAM, M_WAITOK);
|
||||
iores->io.iops = &bhnd_nvram_iores_ops;
|
||||
iores->res = r;
|
||||
iores->offset = offset;
|
||||
iores->size = size;
|
||||
iores->bus_width = bus_width;
|
||||
|
||||
return (&iores->io);
|
||||
}
|
||||
|
||||
static void
|
||||
bhnd_nvram_iores_free(struct bhnd_nvram_io *io)
|
||||
{
|
||||
free(io, M_BHND_NVRAM);
|
||||
}
|
||||
|
||||
static size_t
|
||||
bhnd_nvram_iores_getsize(struct bhnd_nvram_io *io)
|
||||
{
|
||||
struct bhnd_nvram_iores *iores = (struct bhnd_nvram_iores *)io;
|
||||
return (iores->size);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iores_setsize(struct bhnd_nvram_io *io, size_t size)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iores_read_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
const void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iores_write_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate @p offset and @p nbytes:
|
||||
*
|
||||
* - Verify that @p offset is mapped by the backing resource.
|
||||
* - If less than @p nbytes are available at @p offset, write the actual number
|
||||
* of bytes available to @p nbytes.
|
||||
* - Verify that @p offset + @p nbytes are correctly aligned.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_iores_validate_req(struct bhnd_nvram_iores *iores, size_t offset,
|
||||
size_t *nbytes)
|
||||
{
|
||||
/* Verify offset falls within the resource range */
|
||||
if (offset > iores->size)
|
||||
return (ENXIO);
|
||||
|
||||
/* Check for eof */
|
||||
if (offset == iores->size) {
|
||||
*nbytes = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Verify offset alignment */
|
||||
if (offset % iores->bus_width != 0)
|
||||
return (EFAULT);
|
||||
|
||||
/* Limit nbytes to available range and verify size alignment */
|
||||
*nbytes = ummin(*nbytes, iores->size - offset);
|
||||
if (*nbytes < iores->bus_width && *nbytes % iores->bus_width != 0)
|
||||
return (EFAULT);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bhnd_nvram_iores_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||
size_t nbytes)
|
||||
{
|
||||
struct bhnd_nvram_iores *iores;
|
||||
bus_size_t r_offset;
|
||||
size_t navail;
|
||||
int error;
|
||||
|
||||
iores = (struct bhnd_nvram_iores *)io;
|
||||
|
||||
/* Validate the request and determine the actual number of readable
|
||||
* bytes */
|
||||
navail = nbytes;
|
||||
if ((error = bhnd_nvram_iores_validate_req(iores, offset, &navail)))
|
||||
return (error);
|
||||
|
||||
/* At least nbytes must be readable */
|
||||
if (navail < nbytes)
|
||||
return (ENXIO);
|
||||
|
||||
/* Handle zero length read */
|
||||
if (nbytes == 0)
|
||||
return (0);
|
||||
|
||||
/* Determine actual resource offset and perform the read */
|
||||
r_offset = iores->offset + offset;
|
||||
switch (iores->bus_width) {
|
||||
case 1:
|
||||
bhnd_bus_read_region_stream_1(iores->res, r_offset, buffer,
|
||||
nbytes);
|
||||
break;
|
||||
case 2:
|
||||
bhnd_bus_read_region_stream_2(iores->res, r_offset, buffer,
|
||||
nbytes / 2);
|
||||
break;
|
||||
case 4:
|
||||
bhnd_bus_read_region_stream_4(iores->res, r_offset, buffer,
|
||||
nbytes / 4);
|
||||
break;
|
||||
default:
|
||||
panic("unreachable!");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iores_write(struct bhnd_nvram_io *io, size_t offset,
|
||||
void *buffer, size_t nbytes)
|
||||
{
|
||||
struct bhnd_nvram_iores *iores;
|
||||
size_t navail;
|
||||
bus_size_t r_offset;
|
||||
int error;
|
||||
|
||||
iores = (struct bhnd_nvram_iores *)io;
|
||||
|
||||
/* Validate the request and determine the actual number of writable
|
||||
* bytes */
|
||||
navail = nbytes;
|
||||
if ((error = bhnd_nvram_iores_validate_req(iores, offset, &navail)))
|
||||
return (error);
|
||||
|
||||
/* At least nbytes must be writable */
|
||||
if (navail < nbytes)
|
||||
return (ENXIO);
|
||||
|
||||
/* Determine actual resource offset and perform the write */
|
||||
r_offset = iores->offset + offset;
|
||||
switch (iores->bus_width) {
|
||||
case 1:
|
||||
bhnd_bus_write_region_stream_1(iores->res, r_offset, buffer,
|
||||
nbytes);
|
||||
break;
|
||||
case 2:
|
||||
bhnd_bus_write_region_stream_2(iores->res, r_offset, buffer,
|
||||
nbytes / 2);
|
||||
break;
|
||||
case 4:
|
||||
bhnd_bus_write_region_stream_4(iores->res, r_offset, buffer,
|
||||
nbytes / 4);
|
||||
break;
|
||||
default:
|
||||
panic("unreachable!");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
106
sys/dev/bhnd/nvram/bhnd_nvram_iovar.h
Normal file
106
sys/dev/bhnd/nvram/bhnd_nvram_iovar.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_IOVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_IOVAR_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
/** @see bhnd_nvram_io_read() */
|
||||
typedef int (bhnd_nvram_iop_read)(struct bhnd_nvram_io *io, size_t offset,
|
||||
void *buffer, size_t nbytes);
|
||||
|
||||
/** @see bhnd_nvram_io_read_ptr() */
|
||||
typedef int (bhnd_nvram_iop_read_ptr)(struct bhnd_nvram_io *io, size_t offset,
|
||||
const void **ptr, size_t nbytes, size_t *navail);
|
||||
|
||||
/** @see bhnd_nvram_io_write() */
|
||||
typedef int (bhnd_nvram_iop_write)(struct bhnd_nvram_io *io, size_t offset,
|
||||
void *buffer, size_t nbytes);
|
||||
|
||||
/** @see bhnd_nvram_io_write_ptr() */
|
||||
typedef int (bhnd_nvram_iop_write_ptr)(struct bhnd_nvram_io *io, size_t offset,
|
||||
void **ptr, size_t nbytes, size_t *navail);
|
||||
|
||||
/** @see bhnd_nvram_io_getsize() */
|
||||
typedef size_t (bhnd_nvram_iop_getsize)(struct bhnd_nvram_io *io);
|
||||
|
||||
/** @see bhnd_nvram_io_setsize() */
|
||||
typedef int (bhnd_nvram_iop_setsize)(struct bhnd_nvram_io *io, size_t size);
|
||||
|
||||
/** @see bhnd_nvram_io_free() */
|
||||
typedef void (bhnd_nvram_iop_free)(struct bhnd_nvram_io *io);
|
||||
|
||||
/**
|
||||
* NVRAM abstract I/O operations.
|
||||
*/
|
||||
struct bhnd_nvram_iops {
|
||||
bhnd_nvram_iop_read *read; /**< read() implementation */
|
||||
bhnd_nvram_iop_read_ptr *read_ptr; /**< read_ptr() implementation */
|
||||
bhnd_nvram_iop_getsize *getsize; /**< getsize() implementation */
|
||||
bhnd_nvram_iop_setsize *setsize; /**< setsize() implementation */
|
||||
bhnd_nvram_iop_write *write; /**< write() implementation */
|
||||
bhnd_nvram_iop_write_ptr *write_ptr; /**< write_ptr() implementation */
|
||||
bhnd_nvram_iop_free *free; /**< free() implementation */
|
||||
};
|
||||
|
||||
/**
|
||||
* NVRAM abstract I/O context.
|
||||
*/
|
||||
struct bhnd_nvram_io {
|
||||
const struct bhnd_nvram_iops *iops;
|
||||
};
|
||||
|
||||
/**
|
||||
* Declare a bhnd_nvram_iops class with name @p _n.
|
||||
*/
|
||||
#define BHND_NVRAM_IOPS_DEFN(_n) \
|
||||
static bhnd_nvram_iop_read bhnd_nvram_ ## _n ## _read; \
|
||||
static bhnd_nvram_iop_read_ptr bhnd_nvram_ ## _n ## _read_ptr; \
|
||||
static bhnd_nvram_iop_write bhnd_nvram_ ## _n ## _write; \
|
||||
static bhnd_nvram_iop_write_ptr bhnd_nvram_ ## _n ## _write_ptr;\
|
||||
static bhnd_nvram_iop_getsize bhnd_nvram_ ## _n ## _getsize; \
|
||||
static bhnd_nvram_iop_setsize bhnd_nvram_ ## _n ## _setsize; \
|
||||
static bhnd_nvram_iop_free bhnd_nvram_ ## _n ## _free; \
|
||||
\
|
||||
static struct bhnd_nvram_iops bhnd_nvram_ ## _n ## _ops = { \
|
||||
.read = bhnd_nvram_ ## _n ## _read, \
|
||||
.read_ptr = bhnd_nvram_ ## _n ## _read_ptr, \
|
||||
.write = bhnd_nvram_ ## _n ## _write, \
|
||||
.write_ptr = bhnd_nvram_ ## _n ## _write_ptr, \
|
||||
.getsize = bhnd_nvram_ ## _n ## _getsize, \
|
||||
.setsize = bhnd_nvram_ ## _n ## _setsize, \
|
||||
.free = bhnd_nvram_ ## _n ## _free \
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_IOVAR_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,101 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_PARSER_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_PARSER_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include "bhnd_nvram_common.h"
|
||||
|
||||
union bhnd_nvram_ident;
|
||||
|
||||
struct bhnd_nvram_idx;
|
||||
struct bhnd_nvram_ops;
|
||||
struct bhnd_nvram_devpath;
|
||||
|
||||
struct bhnd_nvram;
|
||||
|
||||
LIST_HEAD(bhnd_nvram_devpaths, bhnd_nvram_devpath);
|
||||
|
||||
int bhnd_nvram_parser_identify(const union bhnd_nvram_ident *ident,
|
||||
bhnd_nvram_format expected);
|
||||
int bhnd_nvram_parser_init(struct bhnd_nvram *sc, device_t owner,
|
||||
const void *data, size_t len, bhnd_nvram_format fmt);
|
||||
void bhnd_nvram_parser_fini(struct bhnd_nvram *sc);
|
||||
|
||||
int bhnd_nvram_parser_getvar(struct bhnd_nvram *sc, const char *name,
|
||||
void *buf, size_t *len, bhnd_nvram_type type);
|
||||
int bhnd_nvram_parser_setvar(struct bhnd_nvram *sc, const char *name,
|
||||
const void *buf, size_t len, bhnd_nvram_type type);
|
||||
|
||||
/** BCM NVRAM header */
|
||||
struct bhnd_nvram_header {
|
||||
uint32_t magic;
|
||||
uint32_t size;
|
||||
uint32_t cfg0; /**< crc:8, version:8, sdram_init:16 */
|
||||
uint32_t cfg1; /**< sdram_config:16, sdram_refresh:16 */
|
||||
uint32_t sdram_ncdl; /**< sdram_ncdl */
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* NVRAM format identification.
|
||||
*
|
||||
* To perform identification of the NVRAM format using bhnd_nvram_identify(),
|
||||
* read `sizeof(bhnd_nvram_indent)` bytes from the head of the NVRAM data.
|
||||
*/
|
||||
union bhnd_nvram_ident {
|
||||
struct bhnd_nvram_header bcm;
|
||||
char btxt[4];
|
||||
struct bhnd_tlv_ident {
|
||||
uint8_t tag;
|
||||
uint8_t size[2];
|
||||
uint8_t flags;
|
||||
} __packed tlv;
|
||||
};
|
||||
|
||||
/** bhnd nvram parser instance state */
|
||||
struct bhnd_nvram {
|
||||
device_t dev; /**< parent device, or NULL */
|
||||
const struct bhnd_nvram_ops *ops;
|
||||
uint8_t *buf; /**< nvram data */
|
||||
size_t buf_size;
|
||||
size_t num_buf_vars; /**< number of records in @p buf (0 if not yet calculated) */
|
||||
|
||||
struct bhnd_nvram_idx *idx; /**< key index */
|
||||
|
||||
struct bhnd_nvram_devpaths devpaths; /**< device paths */
|
||||
struct bhnd_nvram_varmap defaults; /**< default values */
|
||||
struct bhnd_nvram_varmap pending; /**< uncommitted writes */
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_PARSER_H_ */
|
@ -1,86 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_PARSERVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_PARSERVAR_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bhnd_nvram_common.h"
|
||||
|
||||
#include "bhnd_nvram_parser.h"
|
||||
|
||||
#define NVRAM_IDX_VAR_THRESH 15 /**< index is generated if minimum variable count is met */
|
||||
#define NVRAM_IDX_OFFSET_MAX UINT16_MAX /**< maximum indexable offset */
|
||||
#define NVRAM_IDX_LEN_MAX UINT8_MAX /**< maximum indexable key/value length */
|
||||
|
||||
#define NVRAM_KEY_MAX 64 /**< maximum key length (not incl. NUL) */
|
||||
#define NVRAM_VAL_MAX 255 /**< maximum value length (not incl. NUL) */
|
||||
|
||||
#define NVRAM_DEVPATH_STR "devpath" /**< name prefix of device path aliases */
|
||||
#define NVRAM_DEVPATH_LEN (sizeof(NVRAM_DEVPATH_STR) - 1)
|
||||
|
||||
#define NVRAM_SMALL_HASH_SIZE 16 /**< hash table size for pending/default tuples */
|
||||
|
||||
/**
|
||||
* NVRAM devpath record.
|
||||
*
|
||||
* Aliases index values to full device paths.
|
||||
*/
|
||||
struct bhnd_nvram_devpath {
|
||||
u_long index; /** alias index */
|
||||
char *path; /** aliased path */
|
||||
|
||||
LIST_ENTRY(bhnd_nvram_devpath) dp_link;
|
||||
};
|
||||
|
||||
/**
|
||||
* NVRAM index record.
|
||||
*
|
||||
* Provides entry offsets into a backing NVRAM buffer.
|
||||
*/
|
||||
struct bhnd_nvram_idx_entry {
|
||||
uint16_t env_offset; /**< offset to env string */
|
||||
uint8_t key_len; /**< key length */
|
||||
uint8_t val_len; /**< value length */
|
||||
};
|
||||
|
||||
/**
|
||||
* NVRAM index.
|
||||
*
|
||||
* Provides a compact binary search index into the backing NVRAM buffer.
|
||||
*/
|
||||
struct bhnd_nvram_idx {
|
||||
size_t num_entries; /**< entry count */
|
||||
struct bhnd_nvram_idx_entry entries[]; /**< index entries */
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_PARSERVAR_H_ */
|
402
sys/dev/bhnd/nvram/bhnd_nvram_private.h
Normal file
402
sys/dev/bhnd/nvram/bhnd_nvram_private.h
Normal file
@ -0,0 +1,402 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_
|
||||
|
||||
/*
|
||||
* Private BHND NVRAM definitions.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "bhnd_nvram.h"
|
||||
#include "bhnd_nvram_value.h"
|
||||
|
||||
/*
|
||||
* bhnd_nvram_crc8() lookup table.
|
||||
*/
|
||||
extern const uint8_t bhnd_nvram_crc8_tab[];
|
||||
|
||||
/* Forward declarations */
|
||||
struct bhnd_nvram_vardefn;
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
MALLOC_DECLARE(M_BHND_NVRAM);
|
||||
|
||||
#define bhnd_nv_isupper(c) isupper(c)
|
||||
#define bhnd_nv_islower(c) islower(c)
|
||||
#define bhnd_nv_isalpha(c) isalpha(c)
|
||||
#define bhnd_nv_isprint(c) isprint(c)
|
||||
#define bhnd_nv_isspace(c) isspace(c)
|
||||
#define bhnd_nv_isdigit(c) isdigit(c)
|
||||
#define bhnd_nv_isxdigit(c) isxdigit(c)
|
||||
#define bhnd_nv_toupper(c) toupper(c)
|
||||
|
||||
#define bhnd_nv_malloc(size) malloc((size), M_BHND_NVRAM, M_WAITOK)
|
||||
#define bhnd_nv_calloc(n, size) malloc((n) * (size), M_BHND_NVRAM, \
|
||||
M_WAITOK | M_ZERO)
|
||||
#define bhnd_nv_reallocf(buf, size) reallocf((buf), (size), M_BHND_NVRAM, \
|
||||
M_WAITOK)
|
||||
#define bhnd_nv_free(buf) free((buf), M_BHND_NVRAM)
|
||||
#define bhnd_nv_strndup(str, len) strndup(str, len, M_BHND_NVRAM)
|
||||
|
||||
#ifdef INVARIANTS
|
||||
#define BHND_NV_INVARIANTS
|
||||
#endif
|
||||
|
||||
#define BHND_NV_ASSERT(expr, ...) KASSERT(expr, __VA_ARGS__)
|
||||
|
||||
#define BHND_NV_VERBOSE (bootverbose)
|
||||
#define BHND_NV_PANIC(...) panic(__VA_ARGS__)
|
||||
#define BHND_NV_LOG(fmt, ...) \
|
||||
printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
|
||||
|
||||
#define bhnd_nv_ummax(a, b) ummax((a), (b))
|
||||
#define bhnd_nv_ummin(a, b) ummin((a), (b))
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ASCII-specific ctype variants that work consistently regardless
|
||||
* of current locale */
|
||||
#define bhnd_nv_isupper(c) ((c) >= 'A' && (c) <= 'Z')
|
||||
#define bhnd_nv_islower(c) ((c) >= 'a' && (c) <= 'z')
|
||||
#define bhnd_nv_isalpha(c) (bhnd_nv_isupper(c) || bhnd_nv_islower(c))
|
||||
#define bhnd_nv_isprint(c) ((c) >= ' ' && (c) <= '~')
|
||||
#define bhnd_nv_isspace(c) ((c) == ' ' || ((c) >= '\t' && (c) <= '\r'))
|
||||
#define bhnd_nv_isdigit(c) isdigit(c)
|
||||
#define bhnd_nv_isxdigit(c) isxdigit(c)
|
||||
#define bhnd_nv_toupper(c) ((c) - \
|
||||
(('a' - 'A') * ((c) >= 'a' && (c) <= 'z')))
|
||||
|
||||
#define bhnd_nv_malloc(size) malloc((size))
|
||||
#define bhnd_nv_calloc(n, size) calloc((n), (size))
|
||||
#define bhnd_nv_reallocf(buf, size) reallocf((buf), (size))
|
||||
#define bhnd_nv_free(buf) free((buf))
|
||||
#define bhnd_nv_strndup(str, len) strndup(str, len)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define BHND_NV_INVARIANTS
|
||||
#endif
|
||||
|
||||
#define BHND_NV_ASSERT(expr, ...) assert(expr)
|
||||
|
||||
#define BHND_NV_VERBOSE (0)
|
||||
#define BHND_NV_PANIC(fmt, ...) do { \
|
||||
fprintf(stderr, "panic: " fmt "\n", ##__VA_ARGS__); \
|
||||
abort(); \
|
||||
} while(0)
|
||||
#define BHND_NV_LOG(fmt, ...) \
|
||||
fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
|
||||
|
||||
static inline uintmax_t
|
||||
bhnd_nv_ummax(uintmax_t a, uintmax_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static inline uintmax_t
|
||||
bhnd_nv_ummin(uintmax_t a, uintmax_t b)
|
||||
{
|
||||
|
||||
return (a < b ? a : b);
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#ifdef BHND_NV_VERBOSE
|
||||
#define BHND_NV_DEBUG(...) BHND_NV_LOG(__VA_ARGS__)
|
||||
#else /* !BHND_NV_VERBOSE */
|
||||
#define BHND_NV_DEBUG(...)
|
||||
#endif /* BHND_NV_VERBOSE */
|
||||
|
||||
/* Limit a size_t value to a suitable range for use as a printf string field
|
||||
* width */
|
||||
#define BHND_NV_PRINT_WIDTH(_len) \
|
||||
((_len) > (INT_MAX) ? (INT_MAX) : (int)(_len))
|
||||
|
||||
int bhnd_nvram_value_coerce(const void *inp,
|
||||
size_t ilen, bhnd_nvram_type itype,
|
||||
void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
int bhnd_nvram_value_nelem(bhnd_nvram_type type,
|
||||
const void *data, size_t len,
|
||||
size_t *nelem);
|
||||
size_t bhnd_nvram_value_size(bhnd_nvram_type type,
|
||||
const void *data, size_t nbytes,
|
||||
size_t nelem);
|
||||
|
||||
int bhnd_nvram_value_printf(const char *fmt,
|
||||
const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, char *outp,
|
||||
size_t *olen, ...);
|
||||
int bhnd_nvram_value_vprintf(const char *fmt,
|
||||
const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, char *outp,
|
||||
size_t *olen, va_list ap);
|
||||
|
||||
const struct bhnd_nvram_vardefn *bhnd_nvram_find_vardefn(const char *varname);
|
||||
const struct bhnd_nvram_vardefn *bhnd_nvram_get_vardefn(size_t id);
|
||||
size_t bhnd_nvram_get_vardefn_id(
|
||||
const struct bhnd_nvram_vardefn *defn);
|
||||
|
||||
int bhnd_nvram_parse_int(const char *s,
|
||||
size_t maxlen, u_int base, size_t *nbytes,
|
||||
void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
int bhnd_nvram_parse_env(const char *env,
|
||||
size_t env_len, char delim,
|
||||
const char **name, size_t *name_len,
|
||||
const char **value, size_t *value_len);
|
||||
|
||||
size_t bhnd_nvram_parse_field(const char **inp,
|
||||
size_t ilen, char delim);
|
||||
size_t bhnd_nvram_trim_field(const char **inp,
|
||||
size_t ilen, char delim);
|
||||
|
||||
bool bhnd_nvram_validate_name(const char *name,
|
||||
size_t name_len);
|
||||
|
||||
/**
|
||||
* Calculate CRC-8 over @p buf using the Broadcom SPROM/NVRAM CRC-8
|
||||
* polynomial.
|
||||
*
|
||||
* @param buf input buffer
|
||||
* @param size buffer size
|
||||
* @param crc last computed crc, or BHND_NVRAM_CRC8_INITIAL
|
||||
*/
|
||||
static inline uint8_t
|
||||
bhnd_nvram_crc8(const void *buf, size_t size, uint8_t crc)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)buf;
|
||||
while (size--)
|
||||
crc = bhnd_nvram_crc8_tab[(crc ^ *p++)];
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
#define BHND_NVRAM_CRC8_INITIAL 0xFF /**< Initial bhnd_nvram_crc8 value */
|
||||
#define BHND_NVRAM_CRC8_VALID 0x9F /**< Valid CRC-8 checksum */
|
||||
|
||||
/** NVRAM variable flags */
|
||||
enum {
|
||||
BHND_NVRAM_VF_MFGINT = 1<<0, /**< mfg-internal variable; should not
|
||||
be externally visible */
|
||||
BHND_NVRAM_VF_IGNALL1 = 1<<1 /**< hide variable if its value has all
|
||||
bits set. */
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM layout flags
|
||||
*/
|
||||
enum {
|
||||
/**
|
||||
* SPROM layout does not have magic identification value.
|
||||
*
|
||||
* This applies to SPROM revisions 1-3, where the actual
|
||||
* layout must be determined by looking for a matching sromrev
|
||||
* at the expected offset, and then verifying the CRC to ensure
|
||||
* that the match was not a false positive.
|
||||
*/
|
||||
SPROM_LAYOUT_MAGIC_NONE = (1<<0),
|
||||
};
|
||||
|
||||
/** NVRAM variable definition */
|
||||
struct bhnd_nvram_vardefn {
|
||||
const char *name; /**< variable name */
|
||||
const char *desc; /**< human readable description,
|
||||
or NULL */
|
||||
const char *help; /**< human readable help text,
|
||||
or NULL */
|
||||
bhnd_nvram_type type; /**< variable type */
|
||||
uint8_t nelem; /**< element count, or 1 if not
|
||||
an array-typed variable */
|
||||
const bhnd_nvram_val_fmt_t *fmt; /**< value format, or NULL */
|
||||
uint32_t flags; /**< flags (BHND_NVRAM_VF_*) */
|
||||
};
|
||||
|
||||
/*
|
||||
* NVRAM variable definitions generated from nvram_map.
|
||||
*/
|
||||
extern const struct bhnd_nvram_vardefn bhnd_nvram_vardefns[];
|
||||
extern const size_t bhnd_nvram_num_vardefns;
|
||||
|
||||
/**
|
||||
* SPROM layout descriptor.
|
||||
*/
|
||||
struct bhnd_sprom_layout {
|
||||
size_t size; /**< SPROM image size, in bytes */
|
||||
uint8_t rev; /**< SPROM revision */
|
||||
uint8_t flags; /**< layout flags (SPROM_LAYOUT_*) */
|
||||
size_t srev_offset; /**< offset to SROM revision */
|
||||
size_t magic_offset; /**< offset to magic value */
|
||||
uint16_t magic_value; /**< expected magic value */
|
||||
const uint8_t *bindings; /**< SPROM binding opcode table */
|
||||
size_t bindings_size; /**< SPROM binding opcode table size */
|
||||
uint16_t num_vars; /**< total number of variables defined
|
||||
for this layout by the binding
|
||||
table */
|
||||
};
|
||||
|
||||
/*
|
||||
* SPROM layout descriptions generated from nvram_map.
|
||||
*/
|
||||
extern const struct bhnd_sprom_layout bhnd_sprom_layouts[];
|
||||
extern const size_t bhnd_sprom_num_layouts;
|
||||
|
||||
/*
|
||||
* SPROM binding opcodes.
|
||||
*
|
||||
* Most opcodes are provided with two variants:
|
||||
*
|
||||
* - Standard: The opcode's data directly follows the opcode. The data type
|
||||
* (SPROM_OPCODE_DATA_*) is encoded in the opcode immediate (IMM).
|
||||
* - Immediate: The opcode's data is encoded directly in the opcode immediate
|
||||
* (IMM).
|
||||
*/
|
||||
#define SPROM_OPC_MASK 0xF0 /**< operation mask */
|
||||
#define SPROM_IMM_MASK 0x0F /**< immediate value mask */
|
||||
#define SPROM_IMM_MAX SPROM_IMM_MASK
|
||||
#define SPROM_OP_DATA_U8 0x00 /**< data is u8 */
|
||||
#define SPROM_OP_DATA_U8_SCALED 0x01 /**< data is u8; multiply by
|
||||
type width */
|
||||
#define SPROM_OP_DATA_U16 0x02 /**< data is u16-le */
|
||||
#define SPROM_OP_DATA_U32 0x03 /**< data is u32-le */
|
||||
#define SPROM_OP_DATA_I8 0x04 /**< data is i8 */
|
||||
#define SPROM_OPCODE_EXT 0x00 /**< extended opcodes defined
|
||||
in IMM */
|
||||
#define SPROM_OPCODE_EOF 0x00 /**< marks end of opcode
|
||||
stream */
|
||||
#define SPROM_OPCODE_NELEM 0x01 /**< variable array element
|
||||
count follows as U8 */
|
||||
#define SPROM_OPCODE_VAR_END 0x02 /**< marks end of variable
|
||||
definition */
|
||||
#define SPROM_OPCODE_TYPE 0x03 /**< input type follows as U8
|
||||
(see BHND_NVRAM_TYPE_*) */
|
||||
#define SPROM_OPCODE_VAR_IMM 0x10 /**< variable ID (imm) */
|
||||
#define SPROM_OPCODE_VAR_REL_IMM 0x20 /**< relative variable ID
|
||||
(last ID + imm) */
|
||||
#define SPROM_OPCODE_VAR 0x30 /**< variable ID */
|
||||
#define SPROM_OPCODE_REV_IMM 0x40 /**< revision range (imm) */
|
||||
#define SPROM_OPCODE_REV_RANGE 0x50 /**< revision range (8-bit range)*/
|
||||
#define SPROM_OP_REV_RANGE_MAX 0x0F /**< maximum representable SROM
|
||||
revision */
|
||||
#define SPROM_OP_REV_START_MASK 0xF0
|
||||
#define SPROM_OP_REV_START_SHIFT 4
|
||||
#define SPROM_OP_REV_END_MASK 0x0F
|
||||
#define SPROM_OP_REV_END_SHIFT 0
|
||||
#define SPROM_OPCODE_MASK_IMM 0x60 /**< value mask (imm) */
|
||||
#define SPROM_OPCODE_MASK 0x70 /**< value mask */
|
||||
#define SPROM_OPCODE_SHIFT_IMM 0x80 /**< value shift (unsigned
|
||||
imm, multipled by 2) */
|
||||
#define SPROM_OPCODE_SHIFT 0x90 /**< value shift */
|
||||
#define SPROM_OPCODE_OFFSET_REL_IMM 0xA0 /**< relative input offset
|
||||
(last offset +
|
||||
(imm * type width)) */
|
||||
#define SPROM_OPCODE_OFFSET 0xB0 /**< input offset */
|
||||
#define SPROM_OPCODE_TYPE_IMM 0xC0 /**< input type (imm,
|
||||
see BHND_NVRAM_TYPE_*) */
|
||||
#define SPROM_OPCODE_DO_BIND 0xD0 /**< bind current value,
|
||||
advance input/output
|
||||
offsets as per IMM */
|
||||
#define SPROM_OP_BIND_SKIP_IN_MASK 0x03 /**< the number of input
|
||||
elements to advance after
|
||||
the bind */
|
||||
#define SPROM_OP_BIND_SKIP_IN_SHIFT 0
|
||||
#define SPROM_OP_BIND_SKIP_IN_SIGN (1<<2) /**< SKIP_IN sign bit */
|
||||
#define SPROM_OP_BIND_SKIP_OUT_MASK 0x08 /**< the number of output
|
||||
elements to advance after
|
||||
the bind */
|
||||
#define SPROM_OP_BIND_SKIP_OUT_SHIFT 3
|
||||
#define SPROM_OPCODE_DO_BINDN_IMM 0xE0 /**< bind IMM times, advancing
|
||||
input/output offsets by one
|
||||
element each time */
|
||||
#define SPROM_OPCODE_DO_BINDN 0xF0 /**< bind N times, advancing
|
||||
input/output offsets as per
|
||||
SPROM_OP_BIND_SKIP_IN/SPROM_OP_BIND_SKIP_OUT
|
||||
IMM values. The U8 element
|
||||
count follows. */
|
||||
|
||||
/** Evaluates to true if opcode is an extended opcode */
|
||||
#define SPROM_OPCODE_IS_EXT(_opcode) \
|
||||
(((_opcode) & SPROM_OPC_MASK) == SPROM_OPCODE_EXT)
|
||||
|
||||
/** Return the opcode constant for a simple or extended opcode */
|
||||
#define SPROM_OPCODE_OP(_opcode) \
|
||||
(SPROM_OPCODE_IS_EXT(_opcode) ? (_opcode) : ((_opcode) & SPROM_OPC_MASK))
|
||||
|
||||
/** Return the opcode immediate for a simple opcode, or zero if this is
|
||||
* an extended opcode */
|
||||
#define SPROM_OPCODE_IMM(_opcode) \
|
||||
(SPROM_OPCODE_IS_EXT(_opcode) ? 0 : ((_opcode) & SPROM_IMM_MASK))
|
||||
|
||||
/** Evaluates to true if the given opcode produces an implicit
|
||||
* SPROM_OPCODE_VAR_END instruction for any open variable */
|
||||
#define SPROM_OP_IS_IMPLICIT_VAR_END(_opcode) \
|
||||
(((_opcode) == SPROM_OPCODE_VAR_IMM) || \
|
||||
((_opcode) == SPROM_OPCODE_VAR_REL_IMM) || \
|
||||
((_opcode) == SPROM_OPCODE_VAR) || \
|
||||
((_opcode) == SPROM_OPCODE_REV_IMM) || \
|
||||
((_opcode) == SPROM_OPCODE_REV_RANGE))
|
||||
|
||||
/** Evaluates to true if the given opcode is either an explicit
|
||||
* SPROM_OPCODE_VAR_END instruction, or is an opcode that produces an
|
||||
* implicit terminatation of any open variable */
|
||||
#define SPROM_OP_IS_VAR_END(_opcode) \
|
||||
(((_opcode) == SPROM_OPCODE_VAR_END) || \
|
||||
SPROM_OP_IS_IMPLICIT_VAR_END(_opcode))
|
||||
|
||||
/** maximum representable immediate value */
|
||||
#define SPROM_OP_IMM_MAX SPROM_IMM_MASK
|
||||
|
||||
/** maximum representable SROM revision */
|
||||
#define SPROM_OP_REV_MAX MAX(SPROM_OP_REV_RANGE_MAX, SPROM_IMM_MAX)
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_PRIVATE_H_ */
|
572
sys/dev/bhnd/nvram/bhnd_nvram_store.c
Normal file
572
sys/dev/bhnd/nvram/bhnd_nvram_store.c
Normal file
@ -0,0 +1,572 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
#include "bhnd_nvram_datavar.h"
|
||||
|
||||
#include "bhnd_nvram_storevar.h"
|
||||
|
||||
/*
|
||||
* BHND NVRAM Store
|
||||
*
|
||||
* Manages in-memory and persistent representations of NVRAM data.
|
||||
*/
|
||||
|
||||
static int bhnd_nvram_sort_idx(void *ctx, const void *lhs,
|
||||
const void *rhs);
|
||||
static int bhnd_nvram_generate_index(struct bhnd_nvram_store *sc);
|
||||
static void *bhnd_nvram_index_lookup(struct bhnd_nvram_store *sc,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new NVRAM data store instance.
|
||||
*
|
||||
* The caller is responsible for deallocating the instance via
|
||||
* bhnd_nvram_store_free().
|
||||
*
|
||||
* @param[out] store On success, a pointer to the newly allocated NVRAM data
|
||||
* instance.
|
||||
* @param data The NVRAM data to be managed by the returned NVRAM data store
|
||||
* instance.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero if an error occurs during allocation or initialization, a
|
||||
* regular unix error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_store_new(struct bhnd_nvram_store **store,
|
||||
struct bhnd_nvram_data *data)
|
||||
{
|
||||
struct bhnd_nvram_store *sc;
|
||||
int error;
|
||||
|
||||
/* Allocate new instance */
|
||||
sc = bhnd_nv_calloc(1, sizeof(*sc));
|
||||
if (sc == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
LIST_INIT(&sc->paths);
|
||||
|
||||
/* Retain the NVRAM data */
|
||||
sc->nv = bhnd_nvram_data_retain(data);
|
||||
|
||||
/* Allocate uncommitted change list */
|
||||
sc->pending = nvlist_create(NV_FLAG_IGNORE_CASE);
|
||||
if (sc->pending == NULL) {
|
||||
error = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Generate all indices */
|
||||
if ((error = bhnd_nvram_generate_index(sc)))
|
||||
goto cleanup;
|
||||
|
||||
BHND_NVSTORE_LOCK_INIT(sc);
|
||||
|
||||
*store = sc;
|
||||
return (0);
|
||||
|
||||
cleanup:
|
||||
bhnd_nvram_store_free(sc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new NVRAM data store instance, parsing the
|
||||
* NVRAM data from @p io.
|
||||
*
|
||||
* The caller is responsible for deallocating the instance via
|
||||
* bhnd_nvram_store_free().
|
||||
*
|
||||
* The NVRAM data mapped by @p io will be copied, and @p io may be safely
|
||||
* deallocated after bhnd_nvram_store_new() returns.
|
||||
*
|
||||
* @param[out] store On success, a pointer to the newly allocated NVRAM data
|
||||
* instance.
|
||||
* @param io An I/O context mapping the NVRAM data to be copied and parsed.
|
||||
* @param cls The NVRAM data class to be used when parsing @p io, or NULL
|
||||
* to perform runtime identification of the appropriate data class.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero if an error occurs during allocation or initialization, a
|
||||
* regular unix error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_store_parse_new(struct bhnd_nvram_store **store,
|
||||
struct bhnd_nvram_io *io, bhnd_nvram_data_class_t *cls)
|
||||
{
|
||||
struct bhnd_nvram_data *data;
|
||||
int error;
|
||||
|
||||
|
||||
/* Try to parse the data */
|
||||
if ((error = bhnd_nvram_data_new(cls, &data, io)))
|
||||
return (error);
|
||||
|
||||
/* Try to create our new store instance */
|
||||
error = bhnd_nvram_store_new(store, data);
|
||||
bhnd_nvram_data_release(data);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an NVRAM store instance, releasing all associated resources.
|
||||
*
|
||||
* @param sc A store instance previously allocated via
|
||||
* bhnd_nvram_store_new().
|
||||
*/
|
||||
void
|
||||
bhnd_nvram_store_free(struct bhnd_nvram_store *sc)
|
||||
{
|
||||
struct bhnd_nvstore_path *dpath, *dnext;
|
||||
|
||||
LIST_FOREACH_SAFE(dpath, &sc->paths, dp_link, dnext) {
|
||||
bhnd_nv_free(dpath->path);
|
||||
bhnd_nv_free(dpath);
|
||||
}
|
||||
|
||||
if (sc->pending != NULL)
|
||||
nvlist_destroy(sc->pending);
|
||||
|
||||
if (sc->idx != NULL)
|
||||
bhnd_nv_free(sc->idx);
|
||||
|
||||
if (sc->nv != NULL)
|
||||
bhnd_nvram_data_release(sc->nv);
|
||||
|
||||
BHND_NVSTORE_LOCK_DESTROY(sc);
|
||||
bhnd_nv_free(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an NVRAM variable.
|
||||
*
|
||||
* @param sc The NVRAM parser state.
|
||||
* @param name The NVRAM variable name.
|
||||
* @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 requested data type to be written to @p buf.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOENT The requested variable was not found.
|
||||
* @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
|
||||
* small to hold the requested value.
|
||||
* @retval non-zero If reading @p name otherwise fails, a regular unix
|
||||
* error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_store_getvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
void *buf, size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
void *cookiep;
|
||||
const void *inp;
|
||||
size_t ilen;
|
||||
bhnd_nvram_type itype;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Search order:
|
||||
*
|
||||
* - uncommitted changes
|
||||
* - index lookup OR buffer scan
|
||||
*/
|
||||
|
||||
BHND_NVSTORE_LOCK(sc);
|
||||
|
||||
/* Is variable marked for deletion? */
|
||||
if (nvlist_exists_null(sc->pending, name)) {
|
||||
BHND_NVSTORE_UNLOCK(sc);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/* Does an uncommitted value exist? */
|
||||
if (nvlist_exists_string(sc->pending, name)) {
|
||||
/* Uncommited value exists, is not a deletion */
|
||||
inp = nvlist_get_string(sc->pending, name);
|
||||
ilen = strlen(inp) + 1;
|
||||
itype = BHND_NVRAM_TYPE_STRING;
|
||||
|
||||
/* Coerce borrowed data reference before releasing
|
||||
* our lock. */
|
||||
error = bhnd_nvram_value_coerce(inp, ilen, itype, buf, len,
|
||||
type);
|
||||
|
||||
BHND_NVSTORE_UNLOCK(sc);
|
||||
|
||||
return (error);
|
||||
} else if (nvlist_exists(sc->pending, name)) {
|
||||
BHND_NV_PANIC("invalid value type for pending change %s", name);
|
||||
}
|
||||
|
||||
/* Fetch variable from parsed NVRAM data. */
|
||||
if ((cookiep = bhnd_nvram_index_lookup(sc, name)) == NULL) {
|
||||
BHND_NVSTORE_UNLOCK(sc);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/* Let the parser itself perform value coercion */
|
||||
error = bhnd_nvram_data_getvar(sc->nv, cookiep, buf, len, type);
|
||||
BHND_NVSTORE_UNLOCK(sc);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an NVRAM variable.
|
||||
*
|
||||
* @param sc The NVRAM parser state.
|
||||
* @param name The NVRAM variable name.
|
||||
* @param[out] buf The new value.
|
||||
* @param[in,out] len The size of @p buf.
|
||||
* @param type The data type of @p buf.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOENT The requested variable was not found.
|
||||
* @retval EINVAL If @p len does not match the expected variable size.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_store_setvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
const void *buf, size_t len, bhnd_nvram_type type)
|
||||
{
|
||||
const char *inp;
|
||||
char vbuf[512];
|
||||
|
||||
/* Verify name validity */
|
||||
if (!bhnd_nvram_validate_name(name, strlen(name)))
|
||||
return (EINVAL);
|
||||
|
||||
/* Verify buffer size alignment for the given type. If this is a
|
||||
* variable width type, a width of 0 will always pass this check */
|
||||
if (len % bhnd_nvram_value_size(type, buf, len, 1) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* Determine string format (or directly add variable, if a C string) */
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY:
|
||||
// TODO: non-char/string value support
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
inp = buf;
|
||||
|
||||
/* Must not exceed buffer size */
|
||||
if (len > sizeof(vbuf))
|
||||
return (EINVAL);
|
||||
|
||||
/* Must have room for a trailing NUL */
|
||||
if (len == sizeof(vbuf) && inp[len-1] != '\0')
|
||||
return (EINVAL);
|
||||
|
||||
/* Copy out the string value and append trailing NUL */
|
||||
strlcpy(vbuf, buf, len);
|
||||
|
||||
/* Add to pending change list */
|
||||
BHND_NVSTORE_LOCK(sc);
|
||||
nvlist_add_string(sc->pending, name, vbuf);
|
||||
BHND_NVSTORE_UNLOCK(sc);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* sort function for bhnd_nvstore_index cookie values */
|
||||
static int
|
||||
bhnd_nvram_sort_idx(void *ctx, const void *lhs, const void *rhs)
|
||||
{
|
||||
struct bhnd_nvram_store *sc;
|
||||
const char *l_str, *r_str;
|
||||
|
||||
sc = ctx;
|
||||
|
||||
/* Fetch string pointers from the cookiep values */
|
||||
l_str = bhnd_nvram_data_getvar_name(sc->nv, *(void * const *)lhs);
|
||||
r_str = bhnd_nvram_data_getvar_name(sc->nv, *(void * const *)rhs);
|
||||
|
||||
/* Perform comparison */
|
||||
return (strcasecmp(l_str, r_str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and register all device paths and path aliases in @p nvram.
|
||||
*
|
||||
* @param sc The NVRAM parser state.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero If registering device paths fails, a regular unix
|
||||
* error code will be returned.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_register_devpaths(struct bhnd_nvram_store *sc)
|
||||
{
|
||||
const char *name;
|
||||
void *cookiep;
|
||||
int error;
|
||||
|
||||
/* Skip if backing parser does not support device paths */
|
||||
if (!(bhnd_nvram_data_caps(sc->nv) & BHND_NVRAM_DATA_CAP_DEVPATHS))
|
||||
return (0);
|
||||
|
||||
/* Parse and register all device path aliases */
|
||||
cookiep = NULL;
|
||||
while ((name = bhnd_nvram_data_next(sc->nv, &cookiep))) {
|
||||
struct bhnd_nvstore_path *devpath;
|
||||
const char *suffix;
|
||||
char *eptr;
|
||||
char *path;
|
||||
size_t path_len;
|
||||
u_long index;
|
||||
|
||||
path = NULL;
|
||||
|
||||
/* Check for devpath prefix */
|
||||
if (strncmp(name, "devpath", strlen("devpath")) != 0)
|
||||
continue;
|
||||
|
||||
/* Parse index value that should follow a 'devpath' prefix */
|
||||
suffix = name + strlen("devpath");
|
||||
index = strtoul(suffix, &eptr, 10);
|
||||
if (eptr == suffix || *eptr != '\0') {
|
||||
BHND_NV_LOG("invalid devpath variable '%s'\n", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Determine path value length */
|
||||
error = bhnd_nvram_data_getvar(sc->nv, cookiep, NULL, &path_len,
|
||||
BHND_NVRAM_TYPE_STRING);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Allocate path buffer */
|
||||
if ((path = bhnd_nv_malloc(path_len)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Decode to our new buffer */
|
||||
error = bhnd_nvram_data_getvar(sc->nv, cookiep, path, &path_len,
|
||||
BHND_NVRAM_TYPE_STRING);
|
||||
if (error) {
|
||||
bhnd_nv_free(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Register path alias */
|
||||
devpath = bhnd_nv_malloc(sizeof(*devpath));
|
||||
if (devpath == NULL) {
|
||||
bhnd_nv_free(path);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
devpath->index = index;
|
||||
devpath->path = path;
|
||||
LIST_INSERT_HEAD(&sc->paths, devpath, dp_link);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate all indices for the NVRAM data backing @p nvram.
|
||||
*
|
||||
* @param sc The NVRAM parser state.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero If indexing @p nvram fails, a regular unix
|
||||
* error code will be returned.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_generate_index(struct bhnd_nvram_store *sc)
|
||||
{
|
||||
const char *name;
|
||||
void *cookiep;
|
||||
size_t idx_bytes;
|
||||
size_t num_vars;
|
||||
int error;
|
||||
|
||||
/* Parse and register all device path aliases */
|
||||
if ((error = bhnd_nvram_register_devpaths(sc)))
|
||||
return (error);
|
||||
|
||||
/* Skip generating a variable index if threshold is not met ... */
|
||||
num_vars = bhnd_nvram_data_count(sc->nv);
|
||||
if (num_vars < NVRAM_IDX_VAR_THRESH)
|
||||
return (0);
|
||||
|
||||
/* ... or if the backing data instance implements indexed lookup
|
||||
* internally */
|
||||
if (bhnd_nvram_data_caps(sc->nv) & BHND_NVRAM_DATA_CAP_INDEXED)
|
||||
return (0);
|
||||
|
||||
/* Allocate and populate variable index */
|
||||
idx_bytes = sizeof(struct bhnd_nvstore_index) +
|
||||
(sizeof(void *) * num_vars);
|
||||
sc->idx = bhnd_nv_malloc(idx_bytes);
|
||||
if (sc->idx == NULL) {
|
||||
BHND_NV_LOG("error allocating %zu byte index\n", idx_bytes);
|
||||
goto bad_index;
|
||||
}
|
||||
|
||||
sc->idx->num_cookiep = num_vars;
|
||||
|
||||
#ifdef _KERNEL
|
||||
if (bootverbose) {
|
||||
BHND_NV_LOG("allocated %zu byte index for %zu variables\n",
|
||||
idx_bytes, num_vars);
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
cookiep = NULL;
|
||||
for (size_t i = 0; i < sc->idx->num_cookiep; i++) {
|
||||
/* Fetch next entry */
|
||||
name = bhnd_nvram_data_next(sc->nv, &cookiep);
|
||||
|
||||
/* Early EOF */
|
||||
if (name == NULL) {
|
||||
BHND_NV_LOG("indexing failed, expected %zu records "
|
||||
"(got %zu)\n", sc->idx->num_cookiep, i+1);
|
||||
goto bad_index;
|
||||
}
|
||||
|
||||
/* Save the variable's cookiep */
|
||||
sc->idx->cookiep[i] = cookiep;
|
||||
}
|
||||
|
||||
/* Sort the index table */
|
||||
qsort_r(sc->idx->cookiep, sc->idx->num_cookiep,
|
||||
sizeof(sc->idx->cookiep[0]), sc, bhnd_nvram_sort_idx);
|
||||
|
||||
return (0);
|
||||
|
||||
bad_index:
|
||||
/* Fall back on non-indexed access */
|
||||
BHND_NV_LOG("reverting to non-indexed variable lookup\n");
|
||||
if (sc->idx != NULL) {
|
||||
bhnd_nv_free(sc->idx);
|
||||
sc->idx = NULL;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform an index lookup of @p name, returning the associated cookie
|
||||
* value, or NULL if the variable does not exist.
|
||||
*
|
||||
* @param sc The NVRAM parser state.
|
||||
* @param name The variable to search for.
|
||||
*/
|
||||
static void *
|
||||
bhnd_nvram_index_lookup(struct bhnd_nvram_store *sc, const char *name)
|
||||
{
|
||||
void *cookiep;
|
||||
const char *indexed_name;
|
||||
size_t min, mid, max;
|
||||
int order;
|
||||
|
||||
BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
|
||||
|
||||
if (sc->idx == NULL || sc->idx->num_cookiep == 0)
|
||||
return (bhnd_nvram_data_find(sc->nv, name));
|
||||
|
||||
/*
|
||||
* Locate the requested variable using a binary search.
|
||||
*/
|
||||
BHND_NV_ASSERT(sc->idx->num_cookiep > 0,
|
||||
("empty array causes underflow"));
|
||||
min = 0;
|
||||
max = sc->idx->num_cookiep - 1;
|
||||
|
||||
while (max >= min) {
|
||||
/* Select midpoint */
|
||||
mid = (min + max) / 2;
|
||||
cookiep = sc->idx->cookiep[mid];
|
||||
|
||||
/* Determine which side of the partition to search */
|
||||
indexed_name = bhnd_nvram_data_getvar_name(sc->nv, cookiep);
|
||||
order = strcasecmp(indexed_name, name);
|
||||
|
||||
if (order < 0) {
|
||||
/* Search upper partition */
|
||||
min = mid + 1;
|
||||
} else if (order > 0) {
|
||||
/* Search (non-empty) lower partition */
|
||||
if (mid == 0)
|
||||
break;
|
||||
max = mid - 1;
|
||||
} else if (order == 0) {
|
||||
/* Match found */
|
||||
return (cookiep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return (NULL);
|
||||
}
|
@ -29,40 +29,40 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAMVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAMVAR_H_
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_STORE_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_STORE_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/nv.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <errno.h>
|
||||
|
||||
#include "bhnd_nvram_parser.h"
|
||||
#include <nv.h>
|
||||
|
||||
DECLARE_CLASS(bhnd_nvram_driver);
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
int bhnd_nvram_probe(device_t dev);
|
||||
int bhnd_nvram_attach(device_t dev, void *data, size_t size,
|
||||
bhnd_nvram_format fmt);
|
||||
int bhnd_nvram_resume(device_t dev);
|
||||
int bhnd_nvram_suspend(device_t dev);
|
||||
int bhnd_nvram_detach(device_t dev);
|
||||
#include <sys/queue.h>
|
||||
|
||||
/**
|
||||
* bhnd_nvram driver instance state. Must be first member of all subclass
|
||||
* softc structures.
|
||||
*/
|
||||
struct bhnd_nvram_softc {
|
||||
device_t dev;
|
||||
struct mtx mtx; /**< nvram mutex */
|
||||
struct bhnd_nvram nvram; /**< nvram shadow */
|
||||
};
|
||||
#include "bhnd_nvram_data.h"
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
struct bhnd_nvram_store;
|
||||
|
||||
#define BHND_NVRAM_LOCK_INIT(sc) \
|
||||
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
|
||||
"bhnd_nvram lock", MTX_DEF)
|
||||
#define BHND_NVRAM_LOCK(sc) mtx_lock(&(sc)->mtx)
|
||||
#define BHND_NVRAM_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
|
||||
#define BHND_NVRAM_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
|
||||
#define BHND_NVRAM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
|
||||
int bhnd_nvram_store_new(struct bhnd_nvram_store **store,
|
||||
struct bhnd_nvram_data *data);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAMVAR_H_ */
|
||||
int bhnd_nvram_store_parse_new(struct bhnd_nvram_store **store,
|
||||
struct bhnd_nvram_io *io, bhnd_nvram_data_class_t *cls);
|
||||
|
||||
void bhnd_nvram_store_free(struct bhnd_nvram_store *store);
|
||||
|
||||
int bhnd_nvram_store_getvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
void *buf, size_t *len, bhnd_nvram_type type);
|
||||
int bhnd_nvram_store_setvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
const void *buf, size_t len, bhnd_nvram_type type);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_STORE_H_ */
|
111
sys/dev/bhnd/nvram/bhnd_nvram_storevar.h
Normal file
111
sys/dev/bhnd/nvram/bhnd_nvram_storevar.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_STOREVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_STOREVAR_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "bhnd_nvram_store.h"
|
||||
|
||||
/** Index is only generated if minimum variable count is met */
|
||||
#define NVRAM_IDX_VAR_THRESH 15
|
||||
|
||||
#define BHND_NVSTORE_PATH_ALIAS_NONE ULONG_MAX
|
||||
|
||||
LIST_HEAD(bhnd_nvstore_paths, bhnd_nvstore_path);
|
||||
|
||||
/**
|
||||
* NVRAM store path.
|
||||
*/
|
||||
struct bhnd_nvstore_path {
|
||||
char *path; /** relative path */
|
||||
u_long index; /** aliased path index, or
|
||||
BHND_NVSTORE_PATH_IDX_INVALID */
|
||||
|
||||
LIST_ENTRY(bhnd_nvstore_path) dp_link;
|
||||
};
|
||||
|
||||
/**
|
||||
* NVRAM store index.
|
||||
*
|
||||
* Provides effecient name-based lookup by maintaining an array of cached
|
||||
* cookiep values, sorted lexicographically by variable name.
|
||||
*/
|
||||
struct bhnd_nvstore_index {
|
||||
size_t num_cookiep; /**< cookiep count */
|
||||
void *cookiep[]; /**< cookiep values */
|
||||
};
|
||||
|
||||
|
||||
/** bhnd nvram store instance state */
|
||||
struct bhnd_nvram_store {
|
||||
#ifdef _KERNEL
|
||||
struct mtx mtx;
|
||||
#else
|
||||
pthread_mutex_t mtx;
|
||||
#endif
|
||||
struct bhnd_nvram_data *nv; /**< backing data */
|
||||
struct bhnd_nvstore_index *idx; /**< index, or NULL */
|
||||
struct bhnd_nvstore_paths paths; /**< paths */
|
||||
nvlist_t *pending; /**< uncommitted writes */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define BHND_NVSTORE_LOCK_INIT(sc) \
|
||||
mtx_init(&(sc)->mtx, "BHND NVRAM store lock", NULL, MTX_DEF)
|
||||
#define BHND_NVSTORE_LOCK(sc) mtx_lock(&(sc)->mtx)
|
||||
#define BHND_NVSTORE_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
|
||||
#define BHND_NVSTORE_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
|
||||
#define BHND_NVSTORE_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#define BHND_NVSTORE_LOCK_INIT(sc) do { \
|
||||
int error = pthread_mutex_init(&(sc)->mtx, NULL); \
|
||||
if (error) \
|
||||
BHND_NV_PANIC("pthread_mutex_init() failed: %d", \
|
||||
error); \
|
||||
} while(0)
|
||||
|
||||
#define BHND_NVSTORE_LOCK(sc) pthread_mutex_lock(&(sc)->mtx)
|
||||
#define BHND_NVSTORE_UNLOCK(sc) pthread_mutex_unlock(&(sc)->mtx)
|
||||
#define BHND_NVSTORE_LOCK_DESTROY(sc) pthread_mutex_destroy(&(sc)->mtx)
|
||||
#define BHND_NVSTORE_LOCK_ASSERT(sc, what)
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_STOREVAR_H_ */
|
1271
sys/dev/bhnd/nvram/bhnd_nvram_subr.c
Normal file
1271
sys/dev/bhnd/nvram/bhnd_nvram_subr.c
Normal file
File diff suppressed because it is too large
Load Diff
1313
sys/dev/bhnd/nvram/bhnd_nvram_value.c
Normal file
1313
sys/dev/bhnd/nvram/bhnd_nvram_value.c
Normal file
File diff suppressed because it is too large
Load Diff
224
sys/dev/bhnd/nvram/bhnd_nvram_value.h
Normal file
224
sys/dev/bhnd/nvram/bhnd_nvram_value.h
Normal file
@ -0,0 +1,224 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_VALUE_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_VALUE_H_
|
||||
|
||||
#include <sys/refcount.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <machine/stdarg.h>
|
||||
#else /* !_KERNEL */
|
||||
#include <stdarg.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram.h"
|
||||
|
||||
typedef struct bhnd_nvram_val_fmt bhnd_nvram_val_fmt_t;
|
||||
typedef struct bhnd_nvram_val bhnd_nvram_val_t;
|
||||
|
||||
int bhnd_nvram_val_init(bhnd_nvram_val_t *value,
|
||||
const bhnd_nvram_val_fmt_t *fmt,
|
||||
const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, uint32_t flags);
|
||||
|
||||
int bhnd_nvram_val_new(bhnd_nvram_val_t **value,
|
||||
const bhnd_nvram_val_fmt_t *fmt,
|
||||
const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, uint32_t flags);
|
||||
|
||||
bhnd_nvram_val_t *bhnd_nvram_val_copy(bhnd_nvram_val_t *value);
|
||||
|
||||
void bhnd_nvram_val_release(
|
||||
bhnd_nvram_val_t *value);
|
||||
|
||||
int bhnd_nvram_val_encode(bhnd_nvram_val_t *value,
|
||||
void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
int bhnd_nvram_val_encode_elem(
|
||||
bhnd_nvram_val_t *value, const void *inp,
|
||||
size_t ilen, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
int bhnd_nvram_val_printf(bhnd_nvram_val_t *value,
|
||||
const char *fmt, char *outp, size_t *olen,
|
||||
...);
|
||||
int bhnd_nvram_val_vprintf(bhnd_nvram_val_t *value,
|
||||
const char *fmt, char *outp, size_t *olen,
|
||||
va_list ap);
|
||||
|
||||
|
||||
const void *bhnd_nvram_val_bytes(bhnd_nvram_val_t *value,
|
||||
size_t *len, bhnd_nvram_type *itype);
|
||||
|
||||
bhnd_nvram_type bhnd_nvram_val_elem_type(
|
||||
bhnd_nvram_val_t *value);
|
||||
|
||||
const void *bhnd_nvram_val_next(bhnd_nvram_val_t *value,
|
||||
const void *prev, size_t *len);
|
||||
|
||||
size_t bhnd_nvram_val_nelem(bhnd_nvram_val_t *value);
|
||||
|
||||
/**
|
||||
* NVRAM value flags
|
||||
*/
|
||||
enum {
|
||||
/**
|
||||
* Do not allocate additional space for value data; all data must be
|
||||
* represented inline within the value structure (default).
|
||||
*/
|
||||
BHND_NVRAM_VAL_FIXED = (0<<0),
|
||||
|
||||
/**
|
||||
* Automatically allocate additional space for value data if it cannot
|
||||
* be represented within the value structure.
|
||||
*/
|
||||
BHND_NVRAM_VAL_DYNAMIC = (1<<0),
|
||||
|
||||
/**
|
||||
* Copy the value data upon initialization. (default).
|
||||
*/
|
||||
BHND_NVRAM_VAL_COPY_DATA = (0<<1),
|
||||
|
||||
/**
|
||||
* Do not perform an initial copy of the value data; the data must
|
||||
* remain valid for the lifetime of the NVRAM value.
|
||||
*
|
||||
* Value data will still be copied if the value itself is copied to the
|
||||
* heap.
|
||||
*/
|
||||
BHND_NVRAM_VAL_BORROW_DATA = (1<<1),
|
||||
|
||||
/**
|
||||
* Do not copy the value data when copying the value to the heap; the
|
||||
* vlaue data is assumed to be statically allocated and must remain
|
||||
* valid for the lifetime of the process.
|
||||
*
|
||||
* Implies BHND_NVRAM_VAL_BORROW_DATA.
|
||||
*/
|
||||
BHND_NVRAM_VAL_STATIC_DATA = (1<<2),
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* NVRAM value storage types.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* The value structure has an automatic or static storage duration
|
||||
* (e.g. it is stack allocated, or is otherwise externally managed),
|
||||
* and no destructors will be run prior to deallocation of the value.
|
||||
*
|
||||
* When performing copy/retain, the existing structure must be copied
|
||||
* to a new heap allocation.
|
||||
*/
|
||||
BHND_NVRAM_VAL_STORAGE_AUTO = 0,
|
||||
|
||||
/**
|
||||
* The value structure was heap allocated and is fully managed by the
|
||||
* the NVRAM value API.
|
||||
*
|
||||
* When performing copy/retain, the existing structure may be retained
|
||||
* as-is.
|
||||
*/
|
||||
BHND_NVRAM_VAL_STORAGE_DYNAMIC = 2,
|
||||
} bhnd_nvram_val_storage_t;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* NVRAM data storage types.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Value has no active representation. This is the default for
|
||||
* zero-initialized value structures. */
|
||||
BHND_NVRAM_VAL_DATA_NONE = 0,
|
||||
|
||||
/** Value data is represented inline */
|
||||
BHND_NVRAM_VAL_DATA_INLINE = 1,
|
||||
|
||||
/**
|
||||
* Value represented by an external reference to data with a static
|
||||
* storage location. The data need not be copied if copying the value.
|
||||
*/
|
||||
BHND_NVRAM_VAL_DATA_EXT_STATIC = 2,
|
||||
|
||||
/**
|
||||
* Value represented by weak external reference, which must be copied
|
||||
* if copying the value */
|
||||
BHND_NVRAM_VAL_DATA_EXT_WEAK = 3,
|
||||
|
||||
/**
|
||||
* Value represented by an external reference that must be deallocated
|
||||
* when deallocating the value
|
||||
*/
|
||||
BHND_NVRAM_VAL_DATA_EXT_ALLOC = 4,
|
||||
} bhnd_nvram_val_data_storage_t;
|
||||
|
||||
/**
|
||||
* NVRAM value
|
||||
*/
|
||||
struct bhnd_nvram_val {
|
||||
volatile u_int refs; /**< reference count */
|
||||
bhnd_nvram_val_storage_t val_storage; /**< value structure storage */
|
||||
const bhnd_nvram_val_fmt_t *fmt; /**< value format, or NULL for default behavior */
|
||||
bhnd_nvram_val_data_storage_t data_storage; /**< data storage */
|
||||
bhnd_nvram_type data_type; /**< data type */
|
||||
size_t data_len; /**< data size */
|
||||
|
||||
/** data representation */
|
||||
union {
|
||||
uint8_t u8[8]; /**< 8-bit unsigned data */
|
||||
uint16_t u16[4]; /**< 16-bit unsigned data */
|
||||
uint32_t u32[2]; /**< 32-bit unsigned data */
|
||||
uint32_t u64[1]; /**< 64-bit unsigned data */
|
||||
int8_t i8[8]; /**< 8-bit signed data */
|
||||
int16_t i16[4]; /**< 16-bit signed data */
|
||||
int32_t i32[2]; /**< 32-bit signed data */
|
||||
int64_t i64[1]; /**< 64-bit signed data */
|
||||
unsigned char ch[8]; /**< 8-bit character data */
|
||||
const void *ptr; /**< external data */
|
||||
} data;
|
||||
};
|
||||
|
||||
/** Declare a bhnd_nvram_val_fmt with name @p _n */
|
||||
#define BHND_NVRAM_VAL_TYPE_DECL(_n) \
|
||||
extern const bhnd_nvram_val_fmt_t bhnd_nvram_val_ ## _n ## _fmt;
|
||||
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_decimal);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_hex);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_leddc);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_macaddr);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_string);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_VALUE_H_ */
|
1032
sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c
Normal file
1032
sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c
Normal file
File diff suppressed because it is too large
Load Diff
883
sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c
Normal file
883
sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c
Normal file
@ -0,0 +1,883 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/sbuf.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/_inttypes.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
#include "bhnd_nvram_valuevar.h"
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define bhnd_nv_hex2ascii(hex) hex2ascii(hex)
|
||||
#else /* !_KERNEL */
|
||||
static char const bhnd_nv_hex2ascii[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
#define bhnd_nv_hex2ascii(hex) (bhnd_nv_hex2ascii[hex])
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/**
|
||||
* Maximum size, in bytes, of a string-encoded NVRAM integer value, not
|
||||
* including any prefix (0x, 0, etc).
|
||||
*
|
||||
* We assume the largest possible encoding is the base-2 representation
|
||||
* of a 64-bit integer.
|
||||
*/
|
||||
#define NV_NUMSTR_MAX ((sizeof(uint64_t) * CHAR_BIT) + 1)
|
||||
|
||||
/**
|
||||
* Format a string representation of @p value using @p fmt, with, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* @param value The value to be formatted.
|
||||
* @param fmt The format string.
|
||||
* @param[out] outp On success, the string will be written to this
|
||||
* buffer. This argment may be NULL if the value is
|
||||
* not desired.
|
||||
* @param[in,out] olen The capacity of @p outp. On success, will be set
|
||||
* to the actual number of bytes required for the
|
||||
* requested string encoding (including a trailing
|
||||
* NUL).
|
||||
*
|
||||
* Refer to bhnd_nvram_val_vprintf() for full format string documentation.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p fmt contains unrecognized format string
|
||||
* specifiers.
|
||||
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
|
||||
* is too small to hold the encoded value.
|
||||
* @retval EFTYPE If value coercion from @p value to a single string
|
||||
* value via @p fmt is unsupported.
|
||||
* @retval ERANGE If value coercion of @p value would overflow (or
|
||||
* underflow) the representation defined by @p fmt.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_val_printf(bhnd_nvram_val_t *value, const char *fmt, char *outp,
|
||||
size_t *olen, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int error;
|
||||
|
||||
va_start(ap, olen);
|
||||
error = bhnd_nvram_val_vprintf(value, fmt, outp, olen, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format a string representation of the elements of @p value using @p fmt,
|
||||
* writing the result to @p outp.
|
||||
*
|
||||
* @param value The value to be formatted.
|
||||
* @param fmt The format string.
|
||||
* @param[out] outp On success, the string will be written to this
|
||||
* buffer. This argment may be NULL if the value is
|
||||
* not desired.
|
||||
* @param[in,out] olen The capacity of @p outp. On success, will be set
|
||||
* to the actual number of bytes required for the
|
||||
* requested string encoding (including a trailing
|
||||
* NUL).
|
||||
* @param ap Argument list.
|
||||
*
|
||||
* @par Format Strings
|
||||
*
|
||||
* Value format strings are similar, but not identical to, those used
|
||||
* by printf(3).
|
||||
*
|
||||
* Format specifier format:
|
||||
* %[repeat][flags][width][.precision][length modifier][specifier]
|
||||
*
|
||||
* The format specifier is interpreted as an encoding directive for an
|
||||
* individual value element; each format specifier will fetch the next element
|
||||
* from the value, encode the element as the appropriate type based on the
|
||||
* length modifiers and specifier, and then format the result as a string.
|
||||
*
|
||||
* For example, given a string value of '0x000F', and a format specifier of
|
||||
* '%#hhx', the value will be asked to encode its first element as
|
||||
* BHND_NVRAM_TYPE_UINT8. String formatting will then be applied to the 8-bit
|
||||
* unsigned integer representation, producing a string value of "0xF".
|
||||
*
|
||||
* Repeat:
|
||||
* - [digits] Repeatedly apply the format specifier to the input
|
||||
* value's elements up to `digits` times. The delimiter
|
||||
* must be passed as a string in the next variadic
|
||||
* argument.
|
||||
* - [] Repeatedly apply the format specifier to the input
|
||||
* value's elements until all elements have been. The
|
||||
* processed. The delimiter must be passed as a string in
|
||||
* the next variadic argument.
|
||||
* - [*] Repeatedly apply the format specifier to the input
|
||||
* value's elements. The repeat count is read from the
|
||||
* next variadic argument as a size_t value
|
||||
*
|
||||
* Flags:
|
||||
* - '#' use alternative form (e.g. 0x/0X prefixing of hex
|
||||
* strings).
|
||||
* - '0' zero padding
|
||||
* - '-' left adjust padding
|
||||
* - '+' include a sign character
|
||||
* - ' ' include a space in place of a sign character for
|
||||
* positive numbers.
|
||||
*
|
||||
* Width/Precision:
|
||||
* - digits minimum field width.
|
||||
* - * read the minimum field width from the next variadic
|
||||
* argument as a ssize_t value. A negative value enables
|
||||
* left adjustment.
|
||||
* - .digits field precision.
|
||||
* - .* read the field precision from the next variadic argument
|
||||
* as a ssize_t value. A negative value enables left
|
||||
* adjustment.
|
||||
*
|
||||
* Length Modifiers:
|
||||
* - 'hh', 'I8' Convert the value to an 8-bit signed or unsigned
|
||||
* integer.
|
||||
* - 'h', 'I16' Convert the value to an 16-bit signed or unsigned
|
||||
* integer.
|
||||
* - 'l', 'I32' Convert the value to an 32-bit signed or unsigned
|
||||
* integer.
|
||||
* - 'll', 'j', 'I64' Convert the value to an 64-bit signed or unsigned
|
||||
* integer.
|
||||
*
|
||||
* Data Specifiers:
|
||||
* - 'd', 'i' Convert and format as a signed decimal integer.
|
||||
* - 'u' Convert and format as an unsigned decimal integer.
|
||||
* - 'o' Convert and format as an unsigned octal integer.
|
||||
* - 'x' Convert and format as an unsigned hexadecimal integer,
|
||||
* using lowercase hex digits.
|
||||
* - 'X' Convert and format as an unsigned hexadecimal integer,
|
||||
* using uppercase hex digits.
|
||||
* - 's' Convert and format as a string.
|
||||
* - '%' Print a literal '%' character.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p fmt contains unrecognized format string
|
||||
* specifiers.
|
||||
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
|
||||
* is too small to hold the encoded value.
|
||||
* @retval EFTYPE If value coercion from @p value to a single string
|
||||
* value via @p fmt is unsupported.
|
||||
* @retval ERANGE If value coercion of @p value would overflow (or
|
||||
* underflow) the representation defined by @p fmt.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_val_vprintf(bhnd_nvram_val_t *value, const char *fmt, char *outp,
|
||||
size_t *olen, va_list ap)
|
||||
{
|
||||
const void *elem;
|
||||
size_t elen;
|
||||
size_t limit, nbytes;
|
||||
int error;
|
||||
|
||||
elem = NULL;
|
||||
|
||||
/* Determine output byte limit */
|
||||
nbytes = 0;
|
||||
if (outp != NULL)
|
||||
limit = *olen;
|
||||
else
|
||||
limit = 0;
|
||||
|
||||
#define WRITE_CHAR(_c) do { \
|
||||
if (limit > nbytes) \
|
||||
*(outp + nbytes) = _c; \
|
||||
\
|
||||
if (nbytes == SIZE_MAX) \
|
||||
return (EFTYPE); \
|
||||
nbytes++; \
|
||||
} while (0)
|
||||
|
||||
/* Encode string value as per the format string */
|
||||
for (const char *p = fmt; *p != '\0'; p++) {
|
||||
const char *delim;
|
||||
size_t precision, width, delim_len;
|
||||
u_long repeat, bits;
|
||||
bool alt_form, ladjust, have_precision;
|
||||
char padc, signc, lenc;
|
||||
|
||||
padc = ' ';
|
||||
signc = '\0';
|
||||
lenc = '\0';
|
||||
delim = "";
|
||||
delim_len = 0;
|
||||
|
||||
ladjust = false;
|
||||
alt_form = false;
|
||||
|
||||
have_precision = false;
|
||||
precision = 1;
|
||||
bits = 32;
|
||||
width = 0;
|
||||
repeat = 1;
|
||||
|
||||
/* Copy all input to output until we hit a format specifier */
|
||||
if (*p != '%') {
|
||||
WRITE_CHAR(*p);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Hit '%' -- is this followed by an escaped '%' literal? */
|
||||
p++;
|
||||
if (*p == '%') {
|
||||
WRITE_CHAR('%');
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Parse repeat specifier */
|
||||
if (*p == '[') {
|
||||
p++;
|
||||
|
||||
/* Determine repeat count */
|
||||
if (*p == ']') {
|
||||
/* Repeat consumes all input */
|
||||
repeat = bhnd_nvram_val_nelem(value);
|
||||
} else if (*p == '*') {
|
||||
/* Repeat is supplied as an argument */
|
||||
repeat = va_arg(ap, size_t);
|
||||
p++;
|
||||
} else {
|
||||
char *endp;
|
||||
|
||||
/* Repeat specified as argument */
|
||||
repeat = strtoul(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
BHND_NV_LOG("error parsing repeat "
|
||||
"count at '%s'", p);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Advance past repeat count */
|
||||
p = endp;
|
||||
}
|
||||
|
||||
/* Advance past terminating ']' */
|
||||
if (*p != ']') {
|
||||
BHND_NV_LOG("error parsing repeat count at "
|
||||
"'%s'", p);
|
||||
return (EINVAL);
|
||||
}
|
||||
p++;
|
||||
|
||||
delim = va_arg(ap, const char *);
|
||||
delim_len = strlen(delim);
|
||||
}
|
||||
|
||||
/* Parse flags */
|
||||
while (*p != '\0') {
|
||||
const char *np;
|
||||
bool stop;
|
||||
|
||||
stop = false;
|
||||
np = p+1;
|
||||
|
||||
switch (*p) {
|
||||
case '#':
|
||||
alt_form = true;
|
||||
break;
|
||||
case '0':
|
||||
padc = '0';
|
||||
break;
|
||||
case '-':
|
||||
ladjust = true;
|
||||
break;
|
||||
case ' ':
|
||||
/* Must not override '+' */
|
||||
if (signc != '+')
|
||||
signc = ' ';
|
||||
break;
|
||||
case '+':
|
||||
signc = '+';
|
||||
break;
|
||||
default:
|
||||
/* Non-flag character */
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stop)
|
||||
break;
|
||||
else
|
||||
p = np;
|
||||
}
|
||||
|
||||
/* Parse minimum width */
|
||||
if (*p == '*') {
|
||||
ssize_t arg;
|
||||
|
||||
/* Width is supplied as an argument */
|
||||
arg = va_arg(ap, int);
|
||||
|
||||
/* Negative width argument is interpreted as
|
||||
* '-' flag followed by positive width */
|
||||
if (arg < 0) {
|
||||
ladjust = true;
|
||||
arg = -arg;
|
||||
}
|
||||
|
||||
width = arg;
|
||||
p++;
|
||||
} else if (bhnd_nv_isdigit(*p)) {
|
||||
uint32_t v;
|
||||
size_t len, parsed;
|
||||
|
||||
/* Parse width value */
|
||||
len = sizeof(v);
|
||||
error = bhnd_nvram_parse_int(p, strlen(p), 10, &parsed,
|
||||
&v, &len, BHND_NVRAM_TYPE_UINT32);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error parsing width %s: %d\n", p,
|
||||
error);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Save width and advance input */
|
||||
width = v;
|
||||
p += parsed;
|
||||
}
|
||||
|
||||
/* Parse precision */
|
||||
if (*p == '.') {
|
||||
uint32_t v;
|
||||
size_t len, parsed;
|
||||
|
||||
p++;
|
||||
have_precision = true;
|
||||
|
||||
if (*p == '*') {
|
||||
ssize_t arg;
|
||||
|
||||
/* Precision is specified as an argument */
|
||||
arg = va_arg(ap, int);
|
||||
|
||||
/* Negative precision argument is interpreted
|
||||
* as '-' flag followed by positive
|
||||
* precision */
|
||||
if (arg < 0) {
|
||||
ladjust = true;
|
||||
arg = -arg;
|
||||
}
|
||||
|
||||
precision = arg;
|
||||
} else if (!bhnd_nv_isdigit(*p)) {
|
||||
/* Implicit precision of 0 */
|
||||
precision = 0;
|
||||
} else {
|
||||
/* Parse precision value */
|
||||
len = sizeof(v);
|
||||
error = bhnd_nvram_parse_int(p, strlen(p), 10,
|
||||
&parsed, &v, &len,
|
||||
BHND_NVRAM_TYPE_UINT32);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error parsing width %s: "
|
||||
"%d\n", p, error);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Save precision and advance input */
|
||||
precision = v;
|
||||
p += parsed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse length modifiers */
|
||||
while (*p != '\0') {
|
||||
const char *np;
|
||||
bool stop;
|
||||
|
||||
stop = false;
|
||||
np = p+1;
|
||||
|
||||
switch (*p) {
|
||||
case 'h':
|
||||
if (lenc == '\0') {
|
||||
/* Set initial length value */
|
||||
lenc = *p;
|
||||
bits = 16;
|
||||
} else if (lenc == *p && bits == 16) {
|
||||
/* Modify previous length value */
|
||||
bits = 8;
|
||||
} else {
|
||||
BHND_NV_LOG("invalid length modifier "
|
||||
"%c\n", *p);
|
||||
return (EINVAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (lenc == '\0') {
|
||||
/* Set initial length value */
|
||||
lenc = *p;
|
||||
bits = 32;
|
||||
} else if (lenc == *p && bits == 32) {
|
||||
/* Modify previous length value */
|
||||
bits = 64;
|
||||
} else {
|
||||
BHND_NV_LOG("invalid length modifier "
|
||||
"%c\n", *p);
|
||||
return (EINVAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
/* Conflicts with all other length
|
||||
* specifications, and may only occur once */
|
||||
if (lenc != '\0') {
|
||||
BHND_NV_LOG("invalid length modifier "
|
||||
"%c\n", *p);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
lenc = *p;
|
||||
bits = 64;
|
||||
break;
|
||||
|
||||
case 'I': {
|
||||
char *endp;
|
||||
|
||||
/* Conflicts with all other length
|
||||
* specifications, and may only occur once */
|
||||
if (lenc != '\0') {
|
||||
BHND_NV_LOG("invalid length modifier "
|
||||
"%c\n", *p);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
lenc = *p;
|
||||
|
||||
/* Parse the length specifier value */
|
||||
p++;
|
||||
bits = strtoul(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
BHND_NV_LOG("invalid size specifier: "
|
||||
"%s\n", p);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Advance input past the parsed integer */
|
||||
np = endp;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Non-length modifier character */
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stop)
|
||||
break;
|
||||
else
|
||||
p = np;
|
||||
}
|
||||
|
||||
/* Parse conversion specifier and format the value(s) */
|
||||
for (u_long n = 0; n < repeat; n++) {
|
||||
bhnd_nvram_type arg_type;
|
||||
size_t arg_size;
|
||||
size_t i;
|
||||
u_long base;
|
||||
bool is_signed, is_upper;
|
||||
|
||||
is_signed = false;
|
||||
is_upper = false;
|
||||
base = 0;
|
||||
|
||||
/* Fetch next element */
|
||||
elem = bhnd_nvram_val_next(value, elem, &elen);
|
||||
if (elem == NULL) {
|
||||
BHND_NV_LOG("format string references more "
|
||||
"than %zu available value elements\n",
|
||||
bhnd_nvram_val_nelem(value));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not the first value, append the delimiter.
|
||||
*/
|
||||
if (n > 0) {
|
||||
size_t nremain = 0;
|
||||
if (limit > nbytes)
|
||||
nremain = limit - nbytes;
|
||||
|
||||
if (nremain >= delim_len)
|
||||
memcpy(outp + nbytes, delim, delim_len);
|
||||
|
||||
/* Add delimiter length to the total byte count */
|
||||
if (SIZE_MAX - nbytes < delim_len)
|
||||
return (EFTYPE); /* overflows size_t */
|
||||
|
||||
nbytes += delim_len;
|
||||
}
|
||||
|
||||
/* Parse integer conversion specifiers */
|
||||
switch (*p) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
base = 10;
|
||||
is_signed = true;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
base = 10;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
base = 16;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
base = 16;
|
||||
is_upper = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Format argument */
|
||||
switch (*p) {
|
||||
#define NV_ENCODE_INT(_width) do { \
|
||||
arg_type = (is_signed) ? BHND_NVRAM_TYPE_INT ## _width : \
|
||||
BHND_NVRAM_TYPE_UINT ## _width; \
|
||||
arg_size = sizeof(v.u ## _width); \
|
||||
error = bhnd_nvram_val_encode_elem(value, elem, elen, \
|
||||
&v.u ## _width, &arg_size, arg_type); \
|
||||
if (error) { \
|
||||
BHND_NV_LOG("error encoding argument as %s: %d\n", \
|
||||
bhnd_nvram_type_name(arg_type), error); \
|
||||
return (error); \
|
||||
} \
|
||||
\
|
||||
if (is_signed) { \
|
||||
if (v.i ## _width < 0) { \
|
||||
add_neg = true; \
|
||||
numval = (int64_t)-(v.i ## _width); \
|
||||
} else { \
|
||||
numval = (int64_t) (v.i ## _width); \
|
||||
} \
|
||||
} else { \
|
||||
numval = v.u ## _width; \
|
||||
} \
|
||||
} while(0)
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
char numbuf[NV_NUMSTR_MAX];
|
||||
char *sptr;
|
||||
uint64_t numval;
|
||||
size_t slen;
|
||||
bool add_neg;
|
||||
union {
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
} v;
|
||||
|
||||
add_neg = false;
|
||||
|
||||
/* If precision is specified, it overrides
|
||||
* (and behaves identically) to a zero-prefixed
|
||||
* minimum width */
|
||||
if (have_precision) {
|
||||
padc = '0';
|
||||
width = precision;
|
||||
ladjust = false;
|
||||
}
|
||||
|
||||
/* If zero-padding is used, value must be right
|
||||
* adjusted */
|
||||
if (padc == '0')
|
||||
ladjust = false;
|
||||
|
||||
/* Request encode to the appropriate integer
|
||||
* type, and then promote to common 64-bit
|
||||
* representation */
|
||||
switch (bits) {
|
||||
case 8:
|
||||
NV_ENCODE_INT(8);
|
||||
break;
|
||||
case 16:
|
||||
NV_ENCODE_INT(16);
|
||||
break;
|
||||
case 32:
|
||||
NV_ENCODE_INT(32);
|
||||
break;
|
||||
case 64:
|
||||
NV_ENCODE_INT(64);
|
||||
break;
|
||||
default:
|
||||
BHND_NV_LOG("invalid length specifier: "
|
||||
"%lu\n", bits);
|
||||
return (EINVAL);
|
||||
}
|
||||
#undef NV_ENCODE_INT
|
||||
|
||||
/* If a precision of 0 is specified and the
|
||||
* value is also zero, no characters should
|
||||
* be produced */
|
||||
if (have_precision && precision == 0 &&
|
||||
numval == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Emit string representation to local buffer */
|
||||
BHND_NV_ASSERT(base <= 16, ("invalid base"));
|
||||
sptr = numbuf + nitems(numbuf) - 1;
|
||||
for (slen = 0; slen < sizeof(numbuf); slen++) {
|
||||
char c;
|
||||
uint64_t n;
|
||||
|
||||
n = numval % base;
|
||||
c = bhnd_nv_hex2ascii(n);
|
||||
if (is_upper)
|
||||
c = bhnd_nv_toupper(c);
|
||||
|
||||
sptr--;
|
||||
*sptr = c;
|
||||
|
||||
numval /= (uint64_t)base;
|
||||
if (numval == 0) {
|
||||
slen++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
arg_size = slen;
|
||||
|
||||
/* Reserve space for 0/0x prefix? */
|
||||
if (alt_form) {
|
||||
if (numval == 0) {
|
||||
/* If 0, no prefix */
|
||||
alt_form = false;
|
||||
} else if (base == 8) {
|
||||
arg_size += 1; /* 0 */
|
||||
} else if (base == 16) {
|
||||
arg_size += 2; /* 0x/0X */
|
||||
}
|
||||
}
|
||||
|
||||
/* Reserve space for ' ', '+', or '-' prefix? */
|
||||
if (add_neg || signc != '\0') {
|
||||
if (add_neg)
|
||||
signc = '-';
|
||||
|
||||
arg_size++;
|
||||
}
|
||||
|
||||
/* Right adjust (if using spaces) */
|
||||
if (!ladjust && padc != '0') {
|
||||
for (i = arg_size; i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
}
|
||||
|
||||
if (signc != '\0')
|
||||
WRITE_CHAR(signc);
|
||||
|
||||
if (alt_form) {
|
||||
if (base == 8) {
|
||||
WRITE_CHAR('0');
|
||||
} else if (base == 16) {
|
||||
WRITE_CHAR('0');
|
||||
if (is_upper)
|
||||
WRITE_CHAR('X');
|
||||
else
|
||||
WRITE_CHAR('x');
|
||||
}
|
||||
}
|
||||
|
||||
/* Right adjust (if using zeros) */
|
||||
if (!ladjust && padc == '0') {
|
||||
for (i = slen; i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
}
|
||||
|
||||
/* Write the string to our output buffer */
|
||||
if (limit > nbytes && limit - nbytes >= slen)
|
||||
memcpy(outp + nbytes, sptr, slen);
|
||||
|
||||
/* Update the total byte count */
|
||||
if (SIZE_MAX - nbytes < arg_size)
|
||||
return (EFTYPE); /* overflows size_t */
|
||||
|
||||
nbytes += arg_size;
|
||||
|
||||
/* Left adjust */
|
||||
for (i = arg_size; ladjust && i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
char *s;
|
||||
size_t slen;
|
||||
|
||||
/* Query the total length of the element when
|
||||
* converted to a string */
|
||||
arg_type = BHND_NVRAM_TYPE_STRING;
|
||||
error = bhnd_nvram_val_encode_elem(value, elem,
|
||||
elen, NULL, &arg_size, arg_type);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error encoding argument "
|
||||
"as %s: %d\n",
|
||||
bhnd_nvram_type_name(arg_type),
|
||||
error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Do not include trailing NUL in the string
|
||||
* length */
|
||||
if (arg_size > 0)
|
||||
arg_size--;
|
||||
|
||||
/* Right adjust */
|
||||
for (i = arg_size; !ladjust && i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
|
||||
/* Determine output positition and remaining
|
||||
* buffer space */
|
||||
if (limit > nbytes) {
|
||||
s = outp + nbytes;
|
||||
slen = limit - nbytes;
|
||||
} else {
|
||||
s = NULL;
|
||||
slen = 0;
|
||||
}
|
||||
|
||||
/* Encode the string to our output buffer */
|
||||
error = bhnd_nvram_val_encode_elem(value, elem,
|
||||
elen, s, &slen, arg_type);
|
||||
if (error && error != ENOMEM) {
|
||||
BHND_NV_LOG("error encoding argument "
|
||||
"as %s: %d\n",
|
||||
bhnd_nvram_type_name(arg_type),
|
||||
error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Update the total byte count */
|
||||
if (SIZE_MAX - nbytes < arg_size)
|
||||
return (EFTYPE); /* overflows size_t */
|
||||
|
||||
nbytes += arg_size;
|
||||
|
||||
/* Left adjust */
|
||||
for (i = arg_size; ladjust && i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c': {
|
||||
char c;
|
||||
|
||||
arg_type = BHND_NVRAM_TYPE_CHAR;
|
||||
arg_size = bhnd_nvram_value_size(arg_type, NULL,
|
||||
0, 1);
|
||||
|
||||
/* Encode as single character */
|
||||
error = bhnd_nvram_val_encode_elem(value, elem,
|
||||
elen, &c, &arg_size, arg_type);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error encoding argument "
|
||||
"as %s: %d\n",
|
||||
bhnd_nvram_type_name(arg_type),
|
||||
error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
BHND_NV_ASSERT(arg_size == sizeof(c),
|
||||
("invalid encoded size"));
|
||||
|
||||
/* Right adjust */
|
||||
for (i = arg_size; !ladjust && i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
|
||||
WRITE_CHAR(padc);
|
||||
|
||||
/* Left adjust */
|
||||
for (i = arg_size; ladjust && i < width; i++)
|
||||
WRITE_CHAR(padc);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Append terminating NUL */
|
||||
if (limit > nbytes)
|
||||
*(outp + nbytes) = '\0';
|
||||
|
||||
if (nbytes < SIZE_MAX)
|
||||
nbytes++;
|
||||
else
|
||||
return (EFTYPE);
|
||||
|
||||
/* Report required space */
|
||||
*olen = nbytes;
|
||||
if (limit < nbytes) {
|
||||
if (outp != NULL)
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
100
sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h
Normal file
100
sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_VALUEVAR_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_VALUEVAR_H_
|
||||
|
||||
#include "bhnd_nvram_value.h"
|
||||
|
||||
int bhnd_nvram_val_generic_encode(bhnd_nvram_val_t *value,
|
||||
void *outp, size_t *olen, bhnd_nvram_type otype);
|
||||
int bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val_t *value,
|
||||
const void *inp, size_t ilen, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
const void *bhnd_nvram_val_generic_next(bhnd_nvram_val_t *value,
|
||||
const void *prev, size_t *len);
|
||||
/**
|
||||
* Filter input data prior to initialization.
|
||||
*
|
||||
* This may be used to permit direct initialization from data types other than
|
||||
* the default native_type defined by @p fmt.
|
||||
*
|
||||
* @param[in,out] fmt Indirect pointer to the NVRAM value format. If
|
||||
* modified by the caller, initialization will be
|
||||
* restarted and performed using the provided
|
||||
* format instance.
|
||||
* @param inp Input data.
|
||||
* @param ilen Input data length.
|
||||
* @param itype Input data type.
|
||||
*
|
||||
* @retval 0 If initialization from @p inp is supported.
|
||||
* @retval EFTYPE If initialization from @p inp is unsupported.
|
||||
* @retval EFAULT if @p ilen is not correctly aligned for elements of
|
||||
* @p itype.
|
||||
*/
|
||||
typedef int (bhnd_nvram_val_op_filter)(const bhnd_nvram_val_fmt_t **fmt,
|
||||
const void *inp, size_t ilen, bhnd_nvram_type itype);
|
||||
|
||||
/** @see bhnd_nvram_val_encode() */
|
||||
typedef int (bhnd_nvram_val_op_encode)(bhnd_nvram_val_t *value, void *outp,
|
||||
size_t *olen, bhnd_nvram_type otype);
|
||||
|
||||
/** @see bhnd_nvram_val_encode_elem() */
|
||||
typedef int (bhnd_nvram_val_op_encode_elem)(bhnd_nvram_val_t *value,
|
||||
const void *inp, size_t ilen, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
/** @see bhnd_nvram_val_next() */
|
||||
typedef const void *(bhnd_nvram_val_op_next)(bhnd_nvram_val_t *value,
|
||||
const void *prev, size_t *len);
|
||||
|
||||
/** @see bhnd_nvram_val_nelem() */
|
||||
typedef size_t (bhnd_nvram_val_op_nelem)(bhnd_nvram_val_t *value);
|
||||
|
||||
/**
|
||||
* NVRAM value format.
|
||||
*
|
||||
* Provides a set of callbacks to support defining custom parsing
|
||||
* and encoding/conversion behavior when representing values as
|
||||
* instances of bhnd_nvram_val.
|
||||
*/
|
||||
struct bhnd_nvram_val_fmt {
|
||||
const char *name; /**< type name */
|
||||
bhnd_nvram_type native_type; /**< native value representation */
|
||||
|
||||
bhnd_nvram_val_op_filter *op_filter;
|
||||
bhnd_nvram_val_op_encode *op_encode;
|
||||
bhnd_nvram_val_op_encode_elem *op_encode_elem;
|
||||
bhnd_nvram_val_op_nelem *op_nelem;
|
||||
bhnd_nvram_val_op_next *op_next;
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_VALUEVAR_H_ */
|
@ -52,15 +52,9 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bhnd_nvram_if.h"
|
||||
|
||||
#include "bhnd_spromvar.h"
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
#define SPROM_LOCK_INIT(sc) \
|
||||
mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
|
||||
"BHND SPROM lock", MTX_DEF)
|
||||
#define SPROM_LOCK(sc) mtx_lock(&(sc)->mtx)
|
||||
#define SPROM_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
|
||||
#define SPROM_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
|
||||
#define SPROM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
|
||||
#include "bhnd_spromvar.h"
|
||||
|
||||
/**
|
||||
* Default bhnd sprom driver implementation of DEVICE_PROBE().
|
||||
@ -68,9 +62,6 @@ __FBSDID("$FreeBSD$");
|
||||
int
|
||||
bhnd_sprom_probe(device_t dev)
|
||||
{
|
||||
/* Quiet by default */
|
||||
if (!bootverbose)
|
||||
device_quiet(dev);
|
||||
device_set_desc(dev, "SPROM/OTP");
|
||||
|
||||
/* Refuse wildcard attachments */
|
||||
@ -100,32 +91,62 @@ int
|
||||
bhnd_sprom_attach(device_t dev, bus_size_t offset)
|
||||
{
|
||||
struct bhnd_sprom_softc *sc;
|
||||
int error;
|
||||
|
||||
struct bhnd_nvram_io *io;
|
||||
struct bhnd_resource *r;
|
||||
bus_size_t r_size, sprom_size;
|
||||
int rid;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
io = NULL;
|
||||
|
||||
/* Allocate SPROM resource */
|
||||
sc->sprom_rid = 0;
|
||||
sc->sprom_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&sc->sprom_rid, RF_ACTIVE);
|
||||
if (sc->sprom_res == NULL) {
|
||||
rid = 0;
|
||||
r = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
||||
if (r == NULL) {
|
||||
device_printf(dev, "failed to allocate resources\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Initialize SPROM shadow */
|
||||
if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, offset)))
|
||||
/* Determine SPROM size */
|
||||
r_size = rman_get_size(r->res);
|
||||
if (r_size <= offset || (r_size - offset) > BUS_SPACE_MAXSIZE) {
|
||||
device_printf(dev, "invalid sprom offset\n");
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
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));
|
||||
if (io == NULL) {
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Initialize NVRAM data store */
|
||||
error = bhnd_nvram_store_parse_new(&sc->store, io,
|
||||
&bhnd_nvram_sprom_class);
|
||||
if (error)
|
||||
goto failed;
|
||||
|
||||
/* Initialize mutex */
|
||||
SPROM_LOCK_INIT(sc);
|
||||
/* Clean up our temporary I/O context and its backing resource */
|
||||
bhnd_nvram_io_free(io);
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
|
||||
|
||||
return (0);
|
||||
|
||||
|
||||
failed:
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
|
||||
sc->sprom_res);
|
||||
/* Clean up I/O context before releasing its backing resource */
|
||||
if (io != NULL)
|
||||
bhnd_nvram_io_free(io);
|
||||
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -157,10 +178,7 @@ bhnd_sprom_detach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
|
||||
sc->sprom_res);
|
||||
bhnd_sprom_fini(&sc->shadow);
|
||||
SPROM_LOCK_DESTROY(sc);
|
||||
bhnd_nvram_store_free(sc->store);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -172,16 +190,9 @@ static int
|
||||
bhnd_sprom_getvar_method(device_t dev, const char *name, void *buf, size_t *len,
|
||||
bhnd_nvram_type type)
|
||||
{
|
||||
struct bhnd_sprom_softc *sc;
|
||||
int error;
|
||||
struct bhnd_sprom_softc *sc = device_get_softc(dev);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
SPROM_LOCK(sc);
|
||||
error = bhnd_sprom_getvar(&sc->shadow, name, buf, len, type);
|
||||
SPROM_UNLOCK(sc);
|
||||
|
||||
return (error);
|
||||
return (bhnd_nvram_store_getvar(sc->store, name, buf, len, type));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,16 +202,9 @@ static int
|
||||
bhnd_sprom_setvar_method(device_t dev, const char *name, const void *buf,
|
||||
size_t len, bhnd_nvram_type type)
|
||||
{
|
||||
struct bhnd_sprom_softc *sc;
|
||||
int error;
|
||||
struct bhnd_sprom_softc *sc = device_get_softc(dev);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
SPROM_LOCK(sc);
|
||||
error = bhnd_sprom_setvar(&sc->shadow, name, buf, len, type);
|
||||
SPROM_UNLOCK(sc);
|
||||
|
||||
return (error);
|
||||
return (bhnd_nvram_store_setvar(sc->store, name, buf, len, type));
|
||||
}
|
||||
|
||||
static device_method_t bhnd_sprom_methods[] = {
|
||||
@ -218,5 +222,5 @@ static device_method_t bhnd_sprom_methods[] = {
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(bhnd_nvram, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc));
|
||||
DEFINE_CLASS_0(bhnd_nvram_store, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc));
|
||||
MODULE_VERSION(bhnd_sprom, 1);
|
||||
|
@ -1,756 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include "bhnd_nvram_common.h"
|
||||
|
||||
#include "bhnd_sprom_parservar.h"
|
||||
|
||||
/*
|
||||
* BHND SPROM Parser
|
||||
*
|
||||
* Provides identification, decoding, and encoding of BHND SPROM data.
|
||||
*/
|
||||
|
||||
static int sprom_direct_read(struct bhnd_sprom *sc, size_t offset,
|
||||
void *buf, size_t nbytes, uint8_t *crc);
|
||||
static int sprom_extend_shadow(struct bhnd_sprom *sc,
|
||||
size_t image_size, uint8_t *crc);
|
||||
static int sprom_populate_shadow(struct bhnd_sprom *sc);
|
||||
|
||||
static int sprom_get_var_defn(struct bhnd_sprom *sc,
|
||||
const char *name,
|
||||
const struct bhnd_nvram_vardefn **var,
|
||||
const struct bhnd_sprom_vardefn **sprom,
|
||||
size_t *size, size_t *nelem,
|
||||
bhnd_nvram_type req_type);
|
||||
|
||||
static char sprom_get_delim_char(struct bhnd_sprom *sc,
|
||||
bhnd_nvram_sfmt sfmt);
|
||||
|
||||
/* SPROM revision is always located at the second-to-last byte */
|
||||
#define SPROM_REV(_sc) SPROM_READ_1((_sc), (_sc)->sp_size - 2)
|
||||
|
||||
/* SPROM CRC is always located at the last byte */
|
||||
#define SPROM_CRC_OFF(_sc) SPROM_CRC_LEN(_sc)
|
||||
|
||||
/* SPROM CRC covers all but the final CRC byte */
|
||||
#define SPROM_CRC_LEN(_sc) ((_sc)->sp_size - 1)
|
||||
|
||||
/* SPROM shadow I/O (with byte-order translation) */
|
||||
#define SPROM_READ_1(_sc, _off) SPROM_READ_ENC_1(_sc, _off)
|
||||
#define SPROM_READ_2(_sc, _off) le16toh(SPROM_READ_ENC_2(_sc, _off))
|
||||
#define SPROM_READ_4(_sc, _off) le32toh(SPROM_READ_ENC_4(_sc, _off))
|
||||
|
||||
#define SPROM_WRITE_1(_sc, _off, _v) SPROM_WRITE_ENC_1(_sc, _off, (_v))
|
||||
#define SPROM_WRITE_2(_sc, _off, _v) SPROM_WRITE_ENC_2(_sc, _off, \
|
||||
htole16(_v))
|
||||
#define SPROM_WRITE_4(_sc, _off, _v) SPROM_WRITE_ENC_4(_sc, _off, \
|
||||
htole32(_v))
|
||||
|
||||
/* SPROM shadow I/O (without byte-order translation) */
|
||||
#define SPROM_READ_ENC_1(_sc, _off) (*(uint8_t *)((_sc)->sp_shadow + _off))
|
||||
#define SPROM_READ_ENC_2(_sc, _off) (*(uint16_t *)((_sc)->sp_shadow + _off))
|
||||
#define SPROM_READ_ENC_4(_sc, _off) (*(uint32_t *)((_sc)->sp_shadow + _off))
|
||||
|
||||
#define SPROM_WRITE_ENC_1(_sc, _off, _v) \
|
||||
*((uint8_t *)((_sc)->sp_shadow + _off)) = (_v)
|
||||
#define SPROM_WRITE_ENC_2(_sc, _off, _v) \
|
||||
*((uint16_t *)((_sc)->sp_shadow + _off)) = (_v)
|
||||
#define SPROM_WRITE_ENC_4(_sc, _off, _v) \
|
||||
*((uint32_t *)((_sc)->sp_shadow + _off)) = (_v)
|
||||
|
||||
/* Call @p _next macro with the C type, widened (signed or unsigned) 32-bit C
|
||||
* type, width, and min/max values associated with @p _dtype */
|
||||
#define SPROM_SWITCH_TYPE(_dtype, _next, ...) \
|
||||
do { \
|
||||
switch (_dtype) { \
|
||||
case BHND_NVRAM_TYPE_UINT8: \
|
||||
_next (uint8_t, uint32_t, 1, 0, \
|
||||
UINT8_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_UINT16: \
|
||||
_next (uint16_t, uint32_t, 2, 0, \
|
||||
UINT16_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_UINT32: \
|
||||
_next (uint32_t, uint32_t, 4, 0, \
|
||||
UINT32_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_INT8: \
|
||||
_next (int8_t, int32_t, 1, \
|
||||
INT8_MIN, INT8_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_INT16: \
|
||||
_next (int16_t, int32_t, 2, \
|
||||
INT16_MIN, INT16_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_INT32: \
|
||||
_next (int32_t, int32_t, 4, \
|
||||
INT32_MIN, INT32_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_CHAR: \
|
||||
_next (char, int32_t, 1, \
|
||||
CHAR_MIN, CHAR_MAX, ## __VA_ARGS__); \
|
||||
break; \
|
||||
case BHND_NVRAM_TYPE_CSTR: \
|
||||
panic("%s: BHND_NVRAM_TYPE_CSTR unhandled", \
|
||||
__FUNCTION__); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Verify the range of _val of (_stype) within _type */
|
||||
#define SPROM_VERIFY_RANGE(_type, _widen, _width, _min, _max, _val, \
|
||||
_stype) \
|
||||
do { \
|
||||
if (BHND_NVRAM_SIGNED_TYPE(_stype)) { \
|
||||
int32_t sval = (int32_t) (_val); \
|
||||
if (sval > (_max) || sval < (_min)) \
|
||||
return (ERANGE); \
|
||||
} else { \
|
||||
if ((_val) > (_max)) \
|
||||
return (ERANGE); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Table of supported SPROM image formats, sorted by image size, ascending.
|
||||
*/
|
||||
#define SPROM_FMT(_sz, _revmin, _revmax, _sig) \
|
||||
{ SPROM_SZ_ ## _sz, _revmin, _revmax, \
|
||||
SPROM_SIG_ ## _sig ## _OFF, \
|
||||
SPROM_SIG_ ## _sig }
|
||||
|
||||
static const struct sprom_fmt {
|
||||
size_t size;
|
||||
uint8_t rev_min;
|
||||
uint8_t rev_max;
|
||||
size_t sig_offset;
|
||||
uint16_t sig_req;
|
||||
} sprom_fmts[] = {
|
||||
SPROM_FMT(R1_3, 1, 3, NONE),
|
||||
SPROM_FMT(R4_8_9, 4, 4, R4),
|
||||
SPROM_FMT(R4_8_9, 8, 9, R8_9),
|
||||
SPROM_FMT(R10, 10, 10, R10),
|
||||
SPROM_FMT(R11, 11, 11, R11)
|
||||
};
|
||||
|
||||
/**
|
||||
* Identify the SPROM format at @p offset within @p r, verify the CRC,
|
||||
* and allocate a local shadow copy of the SPROM data.
|
||||
*
|
||||
* After successful initialization, @p r will not be accessed; any pin
|
||||
* configuration required for SPROM access may be reset.
|
||||
*
|
||||
* @param[out] sprom On success, will be initialized with shadow of the SPROM
|
||||
* data.
|
||||
* @param r An active resource mapping the SPROM data.
|
||||
* @param offset Offset of the SPROM data within @p resource.
|
||||
*/
|
||||
int
|
||||
bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
|
||||
bus_size_t offset)
|
||||
{
|
||||
bus_size_t res_size;
|
||||
int error;
|
||||
|
||||
sprom->dev = rman_get_device(r->res);
|
||||
sprom->sp_res = r;
|
||||
sprom->sp_res_off = offset;
|
||||
|
||||
/* Determine maximum possible SPROM image size */
|
||||
res_size = rman_get_size(r->res);
|
||||
if (offset >= res_size)
|
||||
return (EINVAL);
|
||||
|
||||
sprom->sp_size_max = MIN(res_size - offset, SPROM_SZ_MAX);
|
||||
|
||||
/* Allocate and populate SPROM shadow */
|
||||
sprom->sp_size = 0;
|
||||
sprom->sp_capacity = sprom->sp_size_max;
|
||||
sprom->sp_shadow = malloc(sprom->sp_capacity, M_BHND_NVRAM, M_NOWAIT);
|
||||
if (sprom->sp_shadow == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Read and identify SPROM image */
|
||||
if ((error = sprom_populate_shadow(sprom)))
|
||||
return (error);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources held by @p sprom.
|
||||
*
|
||||
* @param sprom A SPROM instance previously initialized via bhnd_sprom_init().
|
||||
*/
|
||||
void
|
||||
bhnd_sprom_fini(struct bhnd_sprom *sprom)
|
||||
{
|
||||
free(sprom->sp_shadow, M_BHND_NVRAM);
|
||||
}
|
||||
|
||||
/* Perform a read using a SPROM offset descriptor, safely widening the result
|
||||
* to its 32-bit representation before assigning it to @p _dest. */
|
||||
#define SPROM_GETVAR_READ(_type, _widen, _width, _min, _max, _sc, _off, \
|
||||
_dest) \
|
||||
do { \
|
||||
_type _v = (_type)SPROM_READ_ ## _width(_sc, _off->offset); \
|
||||
if (_off->shift > 0) { \
|
||||
_v >>= _off->shift; \
|
||||
} else if (off->shift < 0) { \
|
||||
_v <<= -_off->shift; \
|
||||
} \
|
||||
\
|
||||
if (_off->cont) \
|
||||
_dest |= ((uint32_t) (_widen) _v) & _off->mask; \
|
||||
else \
|
||||
_dest = ((uint32_t) (_widen) _v) & _off->mask; \
|
||||
} while(0)
|
||||
|
||||
/* Emit a value read using a SPROM offset descriptor, narrowing the
|
||||
* result output representation. */
|
||||
#define SPROM_GETVAR_WRITE(_type, _widen, _width, _min, _max, _off, \
|
||||
_src, _buf) \
|
||||
do { \
|
||||
_type _v = (_type) (_widen) _src; \
|
||||
*((_type *)_buf) = _v; \
|
||||
} while(0)
|
||||
|
||||
/* String format a value read using a SPROM offset descriptor */
|
||||
#define SPROM_GETVAR_SNPRINTF(_type, _widen, _width, _min, _max, _src, \
|
||||
_buf, _remain, _fmt, _nwrite) \
|
||||
do { \
|
||||
_nwrite = snprintf(_buf, _remain, _fmt, (_type) (_widen) _src); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Read a SPROM variable, performing conversion to host byte order.
|
||||
*
|
||||
* @param sc The SPROM parser state.
|
||||
* @param name The SPROM variable name.
|
||||
* @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 requested data type to be written to @p buf.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOENT The requested variable was not found.
|
||||
* @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
|
||||
* small to hold the requested value.
|
||||
* @retval non-zero If reading @p name otherwise fails, a regular unix
|
||||
* error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
|
||||
size_t *len, bhnd_nvram_type type)
|
||||
{
|
||||
const struct bhnd_nvram_vardefn *nv;
|
||||
const struct bhnd_sprom_vardefn *sv;
|
||||
void *outp;
|
||||
size_t all1_offs;
|
||||
size_t req_size, nelem;
|
||||
size_t str_remain;
|
||||
char str_delim;
|
||||
uint32_t val;
|
||||
int error;
|
||||
|
||||
error = sprom_get_var_defn(sc, name, &nv, &sv, &req_size, &nelem, type);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
outp = buf;
|
||||
str_remain = 0;
|
||||
str_delim = '\0';
|
||||
|
||||
|
||||
if (type != BHND_NVRAM_TYPE_CSTR) {
|
||||
/* Provide required size */
|
||||
if (outp == NULL) {
|
||||
*len = req_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check (and update) target buffer len */
|
||||
if (*len < req_size)
|
||||
return (ENOMEM);
|
||||
else
|
||||
*len = req_size;
|
||||
} else {
|
||||
/* String length calculation requires performing
|
||||
* the actual string formatting */
|
||||
KASSERT(req_size == 0,
|
||||
("req_size set for variable-length type"));
|
||||
|
||||
/* If caller is querying length, the len argument
|
||||
* may be uninitialized */
|
||||
if (outp != NULL)
|
||||
str_remain = *len;
|
||||
|
||||
/* Fetch delimiter for the variable's string format */
|
||||
str_delim = sprom_get_delim_char(sc, nv->sfmt);
|
||||
}
|
||||
|
||||
/* Read data */
|
||||
all1_offs = 0;
|
||||
val = 0;
|
||||
for (size_t i = 0; i < sv->num_offsets; i++) {
|
||||
const struct bhnd_sprom_offset *off;
|
||||
|
||||
off = &sv->offsets[i];
|
||||
KASSERT(!off->cont || i > 0, ("cont marked on first offset"));
|
||||
|
||||
/* If not a continuation, advance the output buffer; if
|
||||
* a C string, this requires appending a delimiter character */
|
||||
if (i > 0 && !off->cont) {
|
||||
size_t width = bhnd_nvram_type_width(type);
|
||||
|
||||
/* Non-fixed width types (such as CSTR) will have a 0
|
||||
* width value */
|
||||
if (width != 0) {
|
||||
KASSERT(outp != NULL, ("NULL output buffer"));
|
||||
outp = ((uint8_t *)outp) + width;
|
||||
}
|
||||
|
||||
/* Append CSTR delim, if necessary */
|
||||
if (type == BHND_NVRAM_TYPE_CSTR &&
|
||||
str_delim != '\0' &&
|
||||
i != 0)
|
||||
{
|
||||
if (outp != NULL && str_remain >= 1) {
|
||||
*((char *)outp) = str_delim;
|
||||
outp = ((char *)outp + 1);
|
||||
|
||||
/* Drop outp reference if we hit 0 */
|
||||
if (str_remain-- == 0)
|
||||
outp = NULL;
|
||||
}
|
||||
|
||||
if (SIZE_MAX - 1 < req_size)
|
||||
return (EFTYPE); /* too long */
|
||||
req_size++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the value, widening to a common uint32
|
||||
* representation */
|
||||
SPROM_SWITCH_TYPE(off->type, SPROM_GETVAR_READ, sc, off, val);
|
||||
|
||||
/* If IGNALL1, record whether value has all bits set. */
|
||||
if (nv->flags & BHND_NVRAM_VF_IGNALL1) {
|
||||
uint32_t all1;
|
||||
|
||||
all1 = off->mask;
|
||||
if (off->shift > 0)
|
||||
all1 >>= off->shift;
|
||||
else if (off->shift < 0)
|
||||
all1 <<= -off->shift;
|
||||
|
||||
if ((val & all1) == all1)
|
||||
all1_offs++;
|
||||
}
|
||||
|
||||
/* Skip writing if additional continuations remain */
|
||||
if (i+1 < sv->num_offsets && sv->offsets[i].cont)
|
||||
continue;
|
||||
|
||||
/* Perform write */
|
||||
if (type == BHND_NVRAM_TYPE_CSTR) {
|
||||
const char *fmtstr;
|
||||
int written;
|
||||
|
||||
fmtstr = bhnd_nvram_type_fmt(off->type, nv->sfmt, i);
|
||||
if (fmtstr == NULL) {
|
||||
device_printf(sc->dev, "no NVRAM format string "
|
||||
"for '%s' (type=%d)\n", name, off->type);
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
SPROM_SWITCH_TYPE(off->type, SPROM_GETVAR_SNPRINTF, val,
|
||||
outp, str_remain, fmtstr, written);
|
||||
|
||||
if (written <= 0)
|
||||
return (EFTYPE);
|
||||
|
||||
/* Calculate remaining capacity, drop outp reference
|
||||
* if we hit 0 -- otherwise, advance the buffer
|
||||
* position */
|
||||
if (written >= str_remain) {
|
||||
str_remain = 0;
|
||||
outp = NULL;
|
||||
} else {
|
||||
str_remain -= written;
|
||||
if (outp != NULL)
|
||||
outp = (char *)outp + written;
|
||||
}
|
||||
|
||||
/* Add additional bytes to total length */
|
||||
if (SIZE_MAX - written < req_size)
|
||||
return (EFTYPE); /* string too long */
|
||||
req_size += written;
|
||||
} else {
|
||||
/* Verify range */
|
||||
SPROM_SWITCH_TYPE(type, SPROM_VERIFY_RANGE, val,
|
||||
off->type);
|
||||
|
||||
/* Write the value, narrowing to the appropriate output
|
||||
* width. */
|
||||
SPROM_SWITCH_TYPE(type, SPROM_GETVAR_WRITE, off, val,
|
||||
outp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Should value should be treated as uninitialized? */
|
||||
if (nv->flags & BHND_NVRAM_VF_IGNALL1 && all1_offs == sv->num_offsets)
|
||||
return (ENOENT);
|
||||
|
||||
/* If this is a C string request, we need to provide the computed
|
||||
* length. */
|
||||
if (type == BHND_NVRAM_TYPE_CSTR) {
|
||||
/* Account for final trailing NUL */
|
||||
if (SIZE_MAX - 1 < req_size)
|
||||
return (EFTYPE); /* string too long */
|
||||
req_size++;
|
||||
|
||||
/* Return an error if a too-small output buffer was provided */
|
||||
if (buf != NULL && *len < req_size) {
|
||||
*len = req_size;
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
*len = req_size;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Perform a read of a variable offset from _src, safely widening the result
|
||||
* to its 32-bit representation before assigning it to @p _dest. */
|
||||
#define SPROM_SETVAR_READ(_type, _widen, _width, _min, _max, _off, \
|
||||
_src, _dest) \
|
||||
do { \
|
||||
_type _v = *(const _type *)_src; \
|
||||
if (_off->shift > 0) { \
|
||||
_v <<= _off->shift; \
|
||||
} else if (off->shift < 0) { \
|
||||
_v >>= -_off->shift; \
|
||||
} \
|
||||
_dest = ((uint32_t) (_widen) _v) & _off->mask; \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* Emit a value read using a SPROM offset descriptor, narrowing the
|
||||
* result output representation and, if necessary, OR'ing it with the
|
||||
* previously read value from @p _buf. */
|
||||
#define SPROM_SETVAR_WRITE(_type, _widen, _width, _min, _max, _sc, \
|
||||
_off, _src) \
|
||||
do { \
|
||||
_type _v = (_type) (_widen) _src; \
|
||||
if (_off->cont) \
|
||||
_v |= SPROM_READ_ ## _width(_sc, _off->offset); \
|
||||
SPROM_WRITE_ ## _width(_sc, _off->offset, _v); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Set a local value for a SPROM variable, performing conversion to SPROM byte
|
||||
* order.
|
||||
*
|
||||
* The new value will be written to the backing SPROM shadow.
|
||||
*
|
||||
* @param sc The SPROM parser state.
|
||||
* @param name The SPROM variable name.
|
||||
* @param[out] buf The new value.
|
||||
* @param[in,out] len The size of @p buf.
|
||||
* @param type The data type of @p buf.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOENT The requested variable was not found.
|
||||
* @retval EINVAL If @p len does not match the expected variable size.
|
||||
*/
|
||||
int
|
||||
bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name, const void *buf,
|
||||
size_t len, bhnd_nvram_type type)
|
||||
{
|
||||
const struct bhnd_nvram_vardefn *nv;
|
||||
const struct bhnd_sprom_vardefn *sv;
|
||||
size_t req_size, nelem;
|
||||
int error;
|
||||
uint8_t crc;
|
||||
|
||||
error = sprom_get_var_defn(sc, name, &nv, &sv, &req_size, &nelem, type);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* String parsing is currently unsupported */
|
||||
if (type == BHND_NVRAM_TYPE_CSTR)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
/* Provide required size */
|
||||
if (len != req_size)
|
||||
return (EINVAL);
|
||||
|
||||
/* Write data */
|
||||
for (size_t i = 0; i < sv->num_offsets; i++) {
|
||||
const struct bhnd_sprom_offset *off;
|
||||
uint32_t val;
|
||||
|
||||
off = &sv->offsets[i];
|
||||
KASSERT(!off->cont || i > 0, ("cont marked on first offset"));
|
||||
|
||||
/* If not a continuation, advance the input pointer */
|
||||
if (i > 0 && !off->cont) {
|
||||
buf = ((const uint8_t *)buf) +
|
||||
bhnd_nvram_type_width(sv->offsets[i-1].type);
|
||||
}
|
||||
|
||||
/* Read the value, widening to a common uint32
|
||||
* representation */
|
||||
SPROM_SWITCH_TYPE(nv->type, SPROM_SETVAR_READ, off, buf, val);
|
||||
|
||||
/* Verify range */
|
||||
SPROM_SWITCH_TYPE(nv->type, SPROM_VERIFY_RANGE, val, type);
|
||||
|
||||
/* Write the value, narrowing to the appropriate output
|
||||
* width. */
|
||||
SPROM_SWITCH_TYPE(off->type, SPROM_SETVAR_WRITE, sc, off, val);
|
||||
}
|
||||
|
||||
/* Update CRC */
|
||||
crc = ~bhnd_nvram_crc8(sc->sp_shadow, SPROM_CRC_LEN(sc),
|
||||
BHND_NVRAM_CRC8_INITIAL);
|
||||
SPROM_WRITE_1(sc, SPROM_CRC_OFF(sc), crc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read and identify the SPROM image by incrementally performing
|
||||
* read + CRC of all supported image formats */
|
||||
static int
|
||||
sprom_populate_shadow(struct bhnd_sprom *sc)
|
||||
{
|
||||
const struct sprom_fmt *fmt;
|
||||
int error;
|
||||
uint16_t sig;
|
||||
uint8_t srom_rev;
|
||||
uint8_t crc;
|
||||
|
||||
crc = BHND_NVRAM_CRC8_INITIAL;
|
||||
|
||||
/* Identify the SPROM revision (and populate the SPROM shadow) */
|
||||
for (size_t i = 0; i < nitems(sprom_fmts); i++) {
|
||||
fmt = &sprom_fmts[i];
|
||||
|
||||
/* Read image data and check CRC */
|
||||
if ((error = sprom_extend_shadow(sc, fmt->size, &crc)))
|
||||
return (error);
|
||||
|
||||
/* Skip on invalid CRC */
|
||||
if (crc != BHND_NVRAM_CRC8_VALID)
|
||||
continue;
|
||||
|
||||
/* Fetch SROM revision */
|
||||
srom_rev = SPROM_REV(sc);
|
||||
|
||||
/* Early sromrev 1 devices (specifically some BCM440x enet
|
||||
* cards) are reported to have been incorrectly programmed
|
||||
* with a revision of 0x10. */
|
||||
if (fmt->size == SPROM_SZ_R1_3 && srom_rev == 0x10)
|
||||
srom_rev = 0x1;
|
||||
|
||||
/* Verify revision range */
|
||||
if (srom_rev < fmt->rev_min || srom_rev > fmt->rev_max)
|
||||
continue;
|
||||
|
||||
/* Verify signature (if any) */
|
||||
sig = SPROM_SIG_NONE;
|
||||
if (fmt->sig_offset != SPROM_SIG_NONE_OFF)
|
||||
sig = SPROM_READ_2(sc, fmt->sig_offset);
|
||||
|
||||
if (sig != fmt->sig_req) {
|
||||
device_printf(sc->dev,
|
||||
"invalid sprom %hhu signature: 0x%hx "
|
||||
"(expected 0x%hx)\n",
|
||||
srom_rev, sig, fmt->sig_req);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Identified */
|
||||
sc->sp_rev = srom_rev;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* identification failed */
|
||||
device_printf(sc->dev, "unrecognized SPROM format\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extend the shadowed SPROM buffer to image_size, reading any required
|
||||
* data from the backing SPROM resource and updating the CRC.
|
||||
*/
|
||||
static int
|
||||
sprom_extend_shadow(struct bhnd_sprom *sc, size_t image_size,
|
||||
uint8_t *crc)
|
||||
{
|
||||
int error;
|
||||
|
||||
KASSERT(image_size >= sc->sp_size, (("shadow truncation unsupported")));
|
||||
|
||||
/* Verify the request fits within our shadow buffer */
|
||||
if (image_size > sc->sp_capacity)
|
||||
return (ENOSPC);
|
||||
|
||||
/* Skip no-op requests */
|
||||
if (sc->sp_size == image_size)
|
||||
return (0);
|
||||
|
||||
/* Populate the extended range */
|
||||
error = sprom_direct_read(sc, sc->sp_size, sc->sp_shadow + sc->sp_size,
|
||||
image_size - sc->sp_size, crc);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
sc->sp_size = image_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read nbytes at the given offset from the backing SPROM resource, and
|
||||
* update the CRC.
|
||||
*/
|
||||
static int
|
||||
sprom_direct_read(struct bhnd_sprom *sc, size_t offset, void *buf,
|
||||
size_t nbytes, uint8_t *crc)
|
||||
{
|
||||
bus_size_t res_offset;
|
||||
uint16_t *p;
|
||||
|
||||
KASSERT(nbytes % sizeof(uint16_t) == 0, ("unaligned sprom size"));
|
||||
KASSERT(offset % sizeof(uint16_t) == 0, ("unaligned sprom offset"));
|
||||
|
||||
/* Check for read overrun */
|
||||
if (offset >= sc->sp_size_max || sc->sp_size_max - offset < nbytes) {
|
||||
device_printf(sc->dev, "requested SPROM read would overrun\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Perform read and update CRC */
|
||||
p = (uint16_t *)buf;
|
||||
res_offset = sc->sp_res_off + offset;
|
||||
|
||||
bhnd_bus_read_region_stream_2(sc->sp_res, res_offset, p,
|
||||
(nbytes / sizeof(uint16_t)));
|
||||
*crc = bhnd_nvram_crc8(p, nbytes, *crc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Locate the variable and SPROM revision-specific definitions
|
||||
* for variable with @p name.
|
||||
*/
|
||||
static int
|
||||
sprom_get_var_defn(struct bhnd_sprom *sc, const char *name,
|
||||
const struct bhnd_nvram_vardefn **var,
|
||||
const struct bhnd_sprom_vardefn **sprom,
|
||||
size_t *size, size_t *nelem, bhnd_nvram_type req_type)
|
||||
{
|
||||
/* Find variable definition */
|
||||
*var = bhnd_nvram_find_vardefn(name);
|
||||
if (*var == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
/* Find revision-specific SPROM definition */
|
||||
for (size_t i = 0; i < (*var)->num_sp_defs; i++) {
|
||||
const struct bhnd_sprom_vardefn *sp = &(*var)->sp_defs[i];
|
||||
|
||||
if (sc->sp_rev < sp->compat.first)
|
||||
continue;
|
||||
|
||||
if (sc->sp_rev > sp->compat.last)
|
||||
continue;
|
||||
|
||||
/* Found */
|
||||
*sprom = sp;
|
||||
|
||||
/* Calculate element count and total size, in bytes */
|
||||
*nelem = 0;
|
||||
for (size_t j = 0; j < sp->num_offsets; j++)
|
||||
if (!sp->offsets[j].cont)
|
||||
*nelem += 1;
|
||||
|
||||
*size = bhnd_nvram_type_width(req_type) * (*nelem);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Not supported by this SPROM revision */
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array element delimiter for @p sfmt, or '\0' if none.
|
||||
*/
|
||||
static char
|
||||
sprom_get_delim_char(struct bhnd_sprom *sc, bhnd_nvram_sfmt sfmt)
|
||||
{
|
||||
switch (sfmt) {
|
||||
case BHND_NVRAM_SFMT_HEX:
|
||||
case BHND_NVRAM_SFMT_DEC:
|
||||
return (',');
|
||||
|
||||
case BHND_NVRAM_SFMT_CCODE:
|
||||
case BHND_NVRAM_SFMT_LEDDC:
|
||||
return ('\0');
|
||||
|
||||
case BHND_NVRAM_SFMT_MACADDR:
|
||||
return (':');
|
||||
|
||||
default:
|
||||
device_printf(sc->dev, "unknown NVRAM string format: %d\n",
|
||||
sfmt);
|
||||
return (',');
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
|
||||
#include "bhnd_sprom_parser.h"
|
||||
#include "bhnd_nvram_store.h"
|
||||
|
||||
DECLARE_CLASS(bhnd_sprom_driver);
|
||||
|
||||
@ -49,11 +49,8 @@ int bhnd_sprom_detach(device_t dev);
|
||||
* softc structures.
|
||||
*/
|
||||
struct bhnd_sprom_softc {
|
||||
device_t dev;
|
||||
struct bhnd_resource *sprom_res; /**< SPROM resource */
|
||||
int sprom_rid; /**< SPROM RID */
|
||||
struct bhnd_sprom shadow; /**< SPROM shadow */
|
||||
struct mtx mtx; /**< SPROM shadow mutex */
|
||||
device_t dev;
|
||||
struct bhnd_nvram_store *store; /**< nvram store */
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_SPROMVAR_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -111,7 +111,7 @@ bwn_attach(device_t dev)
|
||||
// TODO
|
||||
uint8_t macaddr[6];
|
||||
error = bhnd_nvram_getvar_array(dev, BHND_NVAR_MACADDR, macaddr,
|
||||
sizeof(macaddr), BHND_NVRAM_TYPE_UINT8);
|
||||
sizeof(macaddr), BHND_NVRAM_TYPE_UINT8_ARRAY);
|
||||
if (error)
|
||||
device_printf(dev, "error fetching macaddr: %d\n", error);
|
||||
else
|
||||
|
@ -184,7 +184,7 @@ usb_process(void *arg)
|
||||
|
||||
continue;
|
||||
}
|
||||
/* end if messages - check if anyone is waiting for sync */
|
||||
/* end of messages - check if anyone is waiting for sync */
|
||||
if (up->up_dsleep) {
|
||||
up->up_dsleep = 0;
|
||||
cv_broadcast(&up->up_drain);
|
||||
|
@ -173,6 +173,8 @@ static void rsu_scan_end(struct ieee80211com *);
|
||||
static void rsu_getradiocaps(struct ieee80211com *, int, int *,
|
||||
struct ieee80211_channel[]);
|
||||
static void rsu_set_channel(struct ieee80211com *);
|
||||
static void rsu_scan_curchan(struct ieee80211_scan_state *, unsigned long);
|
||||
static void rsu_scan_mindwell(struct ieee80211_scan_state *);
|
||||
static void rsu_update_mcast(struct ieee80211com *);
|
||||
static int rsu_alloc_rx_list(struct rsu_softc *);
|
||||
static void rsu_free_rx_list(struct rsu_softc *);
|
||||
@ -203,7 +205,8 @@ static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int);
|
||||
static void rsu_set_key(struct rsu_softc *, const struct ieee80211_key *);
|
||||
static void rsu_delete_key(struct rsu_softc *, const struct ieee80211_key *);
|
||||
#endif
|
||||
static int rsu_site_survey(struct rsu_softc *, struct ieee80211vap *);
|
||||
static int rsu_site_survey(struct rsu_softc *,
|
||||
struct ieee80211_scan_ssid *);
|
||||
static int rsu_join_bss(struct rsu_softc *, struct ieee80211_node *);
|
||||
static int rsu_disconnect(struct rsu_softc *);
|
||||
static int rsu_hwrssi_to_rssi(struct rsu_softc *, int hw_rssi);
|
||||
@ -537,6 +540,7 @@ rsu_attach(device_t self)
|
||||
ic->ic_txstream = sc->sc_ntxstream;
|
||||
ic->ic_rxstream = sc->sc_nrxstream;
|
||||
}
|
||||
ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;
|
||||
|
||||
rsu_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
|
||||
ic->ic_channels);
|
||||
@ -547,6 +551,8 @@ rsu_attach(device_t self)
|
||||
ic->ic_scan_end = rsu_scan_end;
|
||||
ic->ic_getradiocaps = rsu_getradiocaps;
|
||||
ic->ic_set_channel = rsu_set_channel;
|
||||
ic->ic_scan_curchan = rsu_scan_curchan;
|
||||
ic->ic_scan_mindwell = rsu_scan_mindwell;
|
||||
ic->ic_vap_create = rsu_vap_create;
|
||||
ic->ic_vap_delete = rsu_vap_delete;
|
||||
ic->ic_update_mcast = rsu_update_mcast;
|
||||
@ -680,16 +686,21 @@ static void
|
||||
rsu_scan_start(struct ieee80211com *ic)
|
||||
{
|
||||
struct rsu_softc *sc = ic->ic_softc;
|
||||
struct ieee80211_scan_state *ss = ic->ic_scan;
|
||||
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
||||
int error;
|
||||
|
||||
/* Scanning is done by the firmware. */
|
||||
RSU_LOCK(sc);
|
||||
/* XXX TODO: force awake if in in network-sleep? */
|
||||
error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps));
|
||||
sc->sc_active_scan = !!(ss->ss_flags & IEEE80211_SCAN_ACTIVE);
|
||||
/* XXX TODO: force awake if in network-sleep? */
|
||||
error = rsu_site_survey(sc, ss->ss_nssid > 0 ? &ss->ss_ssid[0] : NULL);
|
||||
RSU_UNLOCK(sc);
|
||||
if (error != 0)
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev,
|
||||
"could not send site survey command\n");
|
||||
ieee80211_cancel_scan(vap);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -721,6 +732,24 @@ rsu_set_channel(struct ieee80211com *ic __unused)
|
||||
/* We are unable to switch channels, yet. */
|
||||
}
|
||||
|
||||
static void
|
||||
rsu_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
|
||||
{
|
||||
/* Scan is done in rsu_scan_start(). */
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the net80211 framework to indicate
|
||||
* the minimum dwell time has been met, terminate the scan.
|
||||
* We don't actually terminate the scan as the firmware will notify
|
||||
* us when it's finished and we have no way to interrupt it.
|
||||
*/
|
||||
static void
|
||||
rsu_scan_mindwell(struct ieee80211_scan_state *ss)
|
||||
{
|
||||
/* NB: don't try to abort scan; wait for firmware to finish */
|
||||
}
|
||||
|
||||
static void
|
||||
rsu_update_mcast(struct ieee80211com *ic)
|
||||
{
|
||||
@ -1323,31 +1352,36 @@ rsu_delete_key(struct rsu_softc *sc, const struct ieee80211_key *k)
|
||||
#endif
|
||||
|
||||
static int
|
||||
rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap)
|
||||
rsu_site_survey(struct rsu_softc *sc, struct ieee80211_scan_ssid *ssid)
|
||||
{
|
||||
struct r92s_fw_cmd_sitesurvey cmd;
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
int r;
|
||||
|
||||
RSU_ASSERT_LOCKED(sc);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->sc_scan_pass == 1)
|
||||
/* TODO: passive channels? */
|
||||
if (sc->sc_active_scan)
|
||||
cmd.active = htole32(1);
|
||||
cmd.limit = htole32(48);
|
||||
if (sc->sc_scan_pass == 1 && vap->iv_des_nssid > 0) {
|
||||
/* Do a directed scan for second pass. */
|
||||
cmd.ssidlen = htole32(vap->iv_des_ssid[0].len);
|
||||
memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid,
|
||||
vap->iv_des_ssid[0].len);
|
||||
|
||||
|
||||
if (ssid != NULL) {
|
||||
sc->sc_extra_scan = 1;
|
||||
cmd.ssidlen = htole32(ssid->len);
|
||||
memcpy(cmd.ssid, ssid->ssid, ssid->len);
|
||||
}
|
||||
DPRINTF("sending site survey command, pass=%d\n", sc->sc_scan_pass);
|
||||
r = rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd));
|
||||
if (r == 0) {
|
||||
sc->sc_scanning = 1;
|
||||
#ifdef USB_DEBUG
|
||||
if (rsu_debug & (RSU_DEBUG_SCAN | RSU_DEBUG_FWCMD)) {
|
||||
device_printf(sc->sc_dev,
|
||||
"sending site survey command, active %d",
|
||||
le32toh(cmd.active));
|
||||
if (ssid != NULL) {
|
||||
printf(", ssid: ");
|
||||
ieee80211_print_essid(cmd.ssid, le32toh(cmd.ssidlen));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return (r);
|
||||
#endif
|
||||
return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd)));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1362,28 +1396,9 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
|
||||
uint8_t *frm;
|
||||
uint8_t opmode;
|
||||
int error;
|
||||
int cnt;
|
||||
char *msg = "rsujoin";
|
||||
|
||||
RSU_ASSERT_LOCKED(sc);
|
||||
|
||||
/*
|
||||
* Until net80211 scanning doesn't automatically finish
|
||||
* before we tell it to, let's just wait until any pending
|
||||
* scan is done.
|
||||
*
|
||||
* XXX TODO: yes, this releases and re-acquires the lock.
|
||||
* We should re-verify the state whenever we re-attempt this!
|
||||
*/
|
||||
cnt = 0;
|
||||
while (sc->sc_scanning && cnt < 10) {
|
||||
device_printf(sc->sc_dev,
|
||||
"%s: still scanning! (attempt %d)\n",
|
||||
__func__, cnt);
|
||||
msleep(msg, &sc->sc_mtx, 0, msg, hz / 2);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
/* Let the FW decide the opmode based on the capinfo field. */
|
||||
opmode = NDIS802_11AUTOUNKNOWN;
|
||||
RSU_DPRINTF(sc, RSU_DEBUG_RESET,
|
||||
@ -1634,26 +1649,24 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len)
|
||||
break;
|
||||
case R92S_EVT_SURVEY_DONE:
|
||||
RSU_DPRINTF(sc, RSU_DEBUG_SCAN,
|
||||
"%s: site survey pass %d done, found %d BSS\n",
|
||||
__func__, sc->sc_scan_pass, le32toh(*(uint32_t *)buf));
|
||||
sc->sc_scanning = 0;
|
||||
if (vap->iv_state != IEEE80211_S_SCAN)
|
||||
break; /* Ignore if not scanning. */
|
||||
|
||||
/*
|
||||
* XXX TODO: This needs to be done without a transition to
|
||||
* the SCAN state again. Grr.
|
||||
*/
|
||||
if (sc->sc_scan_pass == 0 && vap->iv_des_nssid != 0) {
|
||||
/* Schedule a directed scan for hidden APs. */
|
||||
/* XXX bad! */
|
||||
sc->sc_scan_pass = 1;
|
||||
RSU_UNLOCK(sc);
|
||||
ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
|
||||
RSU_LOCK(sc);
|
||||
"%s: %s scan done, found %d BSS\n",
|
||||
__func__, sc->sc_extra_scan ? "direct" : "broadcast",
|
||||
le32toh(*(uint32_t *)buf));
|
||||
if (sc->sc_extra_scan == 1) {
|
||||
/* Send broadcast probe request. */
|
||||
sc->sc_extra_scan = 0;
|
||||
if (vap != NULL && rsu_site_survey(sc, NULL) != 0) {
|
||||
RSU_UNLOCK(sc);
|
||||
ieee80211_cancel_scan(vap);
|
||||
RSU_LOCK(sc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
sc->sc_scan_pass = 0;
|
||||
if (vap != NULL) {
|
||||
RSU_UNLOCK(sc);
|
||||
ieee80211_scan_done(vap);
|
||||
RSU_LOCK(sc);
|
||||
}
|
||||
break;
|
||||
case R92S_EVT_JOIN_BSS:
|
||||
if (vap->iv_state == IEEE80211_S_AUTH)
|
||||
@ -2920,12 +2933,11 @@ rsu_init(struct rsu_softc *sc)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sc->sc_scan_pass = 0;
|
||||
sc->sc_extra_scan = 0;
|
||||
usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]);
|
||||
|
||||
/* We're ready to go. */
|
||||
sc->sc_running = 1;
|
||||
sc->sc_scanning = 0;
|
||||
return;
|
||||
fail:
|
||||
/* Need to stop all failed transfers, if any */
|
||||
|
@ -573,7 +573,7 @@ struct r92s_tx_desc {
|
||||
#define R92S_TXDW1_QSEL_M 0x00001f00
|
||||
#define R92S_TXDW1_QSEL_S 8
|
||||
#define R92S_TXDW1_QSEL_BE 0x03
|
||||
#define R92S_TXDW1_QSEL_H2C 0x1f
|
||||
#define R92S_TXDW1_QSEL_H2C 0x13
|
||||
#define R92S_TXDW1_NONQOS 0x00010000
|
||||
#define R92S_TXDW1_KEYIDX_M 0x00060000
|
||||
#define R92S_TXDW1_KEYIDX_S 17
|
||||
@ -768,8 +768,8 @@ struct rsu_softc {
|
||||
|
||||
u_int sc_running:1,
|
||||
sc_calibrating:1,
|
||||
sc_scanning:1,
|
||||
sc_scan_pass:1;
|
||||
sc_active_scan:1,
|
||||
sc_extra_scan:1;
|
||||
u_int cut;
|
||||
uint8_t sc_rftype;
|
||||
int8_t sc_nrxstream;
|
||||
|
@ -537,7 +537,8 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
|
||||
struct csum *sump;
|
||||
int error;
|
||||
int ronly;
|
||||
int i, size;
|
||||
int i;
|
||||
u_long size;
|
||||
int32_t *lp;
|
||||
int32_t e2fs_maxcontig;
|
||||
|
||||
|
@ -608,21 +608,6 @@ nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
|
||||
nfsstatsv1.srvcache_nonidemdonehits = 0;
|
||||
nfsstatsv1.srvcache_misses = 0;
|
||||
nfsstatsv1.srvcache_tcppeak = 0;
|
||||
nfsstatsv1.srvclients = 0;
|
||||
nfsstatsv1.srvopenowners = 0;
|
||||
nfsstatsv1.srvopens = 0;
|
||||
nfsstatsv1.srvlockowners = 0;
|
||||
nfsstatsv1.srvlocks = 0;
|
||||
nfsstatsv1.srvdelegates = 0;
|
||||
nfsstatsv1.clopenowners = 0;
|
||||
nfsstatsv1.clopens = 0;
|
||||
nfsstatsv1.cllockowners = 0;
|
||||
nfsstatsv1.cllocks = 0;
|
||||
nfsstatsv1.cldelegates = 0;
|
||||
nfsstatsv1.cllocalopenowners = 0;
|
||||
nfsstatsv1.cllocalopens = 0;
|
||||
nfsstatsv1.cllocallockowners = 0;
|
||||
nfsstatsv1.cllocallocks = 0;
|
||||
bzero(nfsstatsv1.srvrpccnt,
|
||||
sizeof(nfsstatsv1.srvrpccnt));
|
||||
bzero(nfsstatsv1.cbrpccnt,
|
||||
|
@ -1320,6 +1320,8 @@ nfs_mount(struct mount *mp)
|
||||
MNT_ILOCK(mp);
|
||||
mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
|
||||
MNTK_USES_BCACHE;
|
||||
if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
|
||||
mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
|
||||
MNT_IUNLOCK(mp);
|
||||
}
|
||||
return (error);
|
||||
|
@ -188,7 +188,8 @@ nullfs_mount(struct mount *mp)
|
||||
}
|
||||
|
||||
xmp->nullm_flags |= NULLM_CACHE;
|
||||
if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0)
|
||||
if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0 ||
|
||||
(xmp->nullm_vfs->mnt_kern_flag & MNTK_NULL_NOCACHE) != 0)
|
||||
xmp->nullm_flags &= ~NULLM_CACHE;
|
||||
|
||||
MNT_ILOCK(mp);
|
||||
|
@ -3002,7 +3002,7 @@ vinactive(struct vnode *vp, struct thread *td)
|
||||
obj = vp->v_object;
|
||||
if (obj != NULL && (obj->flags & OBJ_MIGHTBEDIRTY) != 0) {
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
vm_object_page_clean(obj, 0, 0, OBJPC_NOSYNC);
|
||||
vm_object_page_clean(obj, 0, 0, 0);
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
}
|
||||
VOP_INACTIVE(vp, td);
|
||||
|
527
sys/mips/broadcom/bcm_nvram_cfe.c
Normal file
527
sys/mips/broadcom/bcm_nvram_cfe.c
Normal file
@ -0,0 +1,527 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* BHND CFE NVRAM driver.
|
||||
*
|
||||
* Provides access to device NVRAM via CFE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
|
||||
#include <dev/cfe/cfe_api.h>
|
||||
#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_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_t **cls);
|
||||
|
||||
/** Known CFE NVRAM device names, in probe order. */
|
||||
static char *nvram_cfe_devs[] = {
|
||||
"nflash0.nvram", /* NAND */
|
||||
"nflash1.nvram",
|
||||
"flash0.nvram",
|
||||
"flash1.nvram",
|
||||
};
|
||||
|
||||
/** Supported CFE NVRAM formats, in probe order. */
|
||||
static bhnd_nvram_data_class_t * const nvram_cfe_fmts[] = {
|
||||
&bhnd_nvram_bcm_class,
|
||||
&bhnd_nvram_tlv_class
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_probe(device_t dev)
|
||||
{
|
||||
struct bhnd_nvram_io *io;
|
||||
bhnd_nvram_data_class_t *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)
|
||||
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);
|
||||
}
|
||||
|
||||
/* Refuse wildcard attachments */
|
||||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_attach(device_t dev)
|
||||
{
|
||||
struct bhnd_nvram_cfe_softc *sc;
|
||||
bhnd_nvram_data_class_t *cls;
|
||||
struct bhnd_nvram_io *io;
|
||||
char *dname;
|
||||
int error;
|
||||
|
||||
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);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_resume(device_t dev)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_suspend(device_t dev)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_detach(device_t dev)
|
||||
{
|
||||
struct bhnd_nvram_cfe_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
bhnd_nvram_store_free(sc->store);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_getvar(device_t dev, const char *name, void *buf, size_t *len,
|
||||
bhnd_nvram_type type)
|
||||
{
|
||||
struct bhnd_nvram_cfe_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (bhnd_nvram_store_getvar(sc->store, name, buf, len, type));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_cfe_setvar(device_t dev, const char *name, const void *buf,
|
||||
size_t len, bhnd_nvram_type type)
|
||||
{
|
||||
struct bhnd_nvram_cfe_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (bhnd_nvram_store_setvar(sc->store, name, buf, len, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find, open, identify, and return an I/O context mapping our
|
||||
* CFE NVRAM device.
|
||||
*
|
||||
* @param dev bhnd_nvram_cfe device.
|
||||
* @param[out] dname On success, the CFE device name.
|
||||
* @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.
|
||||
*/
|
||||
static struct bhnd_nvram_io *
|
||||
bhnd_nvram_find_cfedev(device_t dev, char **dname,
|
||||
bhnd_nvram_data_class_t **cls)
|
||||
{
|
||||
struct bhnd_nvram_io *io;
|
||||
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];
|
||||
|
||||
/* Does the device exist? */
|
||||
if ((devinfo = cfe_getdevinfo(*dname)) < 0) {
|
||||
if (devinfo != CFE_ERR_DEVNOTFOUND) {
|
||||
device_printf(dev, "cfe_getdevinfo(%s) "
|
||||
"failed: %d\n", *dname, devinfo);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Open for reading */
|
||||
if ((error = bhnd_nvram_iocfe_new(&io, *dname)))
|
||||
continue;
|
||||
|
||||
/* Probe */
|
||||
result = bhnd_nvram_data_probe(*cls, io);
|
||||
if (result <= 0) {
|
||||
/* Found a supporting NVRAM data class */
|
||||
return (io);
|
||||
}
|
||||
|
||||
/* Keep searching */
|
||||
bhnd_nvram_io_free(io);
|
||||
io = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate and return a new I/O context backed by a CFE device.
|
||||
*
|
||||
* The caller is responsible for deallocating 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.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
struct bhnd_nvram_iocfe *iocfe;
|
||||
nvram_info_t nvram_info;
|
||||
int cerr, devinfo, dtype, rlen;
|
||||
int64_t nv_offset;
|
||||
u_int nv_size;
|
||||
bool req_blk_erase;
|
||||
int error;
|
||||
|
||||
iocfe = malloc(sizeof(*iocfe), M_DEVBUF, M_WAITOK);
|
||||
iocfe->io.iops = &bhnd_nvram_iocfe_ops;
|
||||
iocfe->dname = dname;
|
||||
|
||||
/* Try to open the device */
|
||||
iocfe->fd = cfe_open(dname);
|
||||
if (iocfe->fd <= 0) {
|
||||
IOCFE_LOG(iocfe, "cfe_open() failed: %d\n", iocfe->fd);
|
||||
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Try to fetch device info */
|
||||
if ((devinfo = cfe_getdevinfo(iocfe->dname)) < 0) {
|
||||
IOCFE_LOG(iocfe, "cfe_getdevinfo() failed: %d\n", devinfo);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Verify device type */
|
||||
dtype = devinfo & CFE_DEV_MASK;
|
||||
switch (dtype) {
|
||||
case CFE_DEV_FLASH:
|
||||
case CFE_DEV_NVRAM:
|
||||
/* Valid device type */
|
||||
break;
|
||||
default:
|
||||
IOCFE_LOG(iocfe, "unknown device type: %d\n", dtype);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Try to fetch nvram info from CFE */
|
||||
cerr = cfe_ioctl(iocfe->fd, IOCTL_NVRAM_GETINFO,
|
||||
(unsigned char *)&nvram_info, sizeof(nvram_info), &rlen, 0);
|
||||
if (cerr == CFE_OK) {
|
||||
/* Sanity check the result; must not be a negative integer */
|
||||
if (nvram_info.nvram_size < 0 ||
|
||||
nvram_info.nvram_offset < 0)
|
||||
{
|
||||
IOCFE_LOG(iocfe, "invalid NVRAM layout (%d/%d)\n",
|
||||
nvram_info.nvram_size, nvram_info.nvram_offset);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
nv_offset = nvram_info.nvram_offset;
|
||||
nv_size = nvram_info.nvram_size;
|
||||
req_blk_erase = (nvram_info.nvram_eraseflg != 0);
|
||||
} else if (cerr != CFE_OK && cerr != CFE_ERR_INV_COMMAND) {
|
||||
IOCFE_LOG(iocfe, "IOCTL_NVRAM_GETINFO failed: %d\n", cerr);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Fall back on flash info.
|
||||
*
|
||||
* This is known to be required on the Asus RT-N53 (CFE 5.70.55.33,
|
||||
* BBP 1.0.37, BCM5358UB0), where IOCTL_NVRAM_GETINFO returns
|
||||
* CFE_ERR_INV_COMMAND.
|
||||
*/
|
||||
if (cerr == CFE_ERR_INV_COMMAND) {
|
||||
flash_info_t fi;
|
||||
|
||||
cerr = cfe_ioctl(iocfe->fd, IOCTL_FLASH_GETINFO,
|
||||
(unsigned char *)&fi, sizeof(fi), &rlen, 0);
|
||||
|
||||
if (cerr != CFE_OK) {
|
||||
IOCFE_LOG(iocfe, "IOCTL_FLASH_GETINFO failed %d\n",
|
||||
cerr);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
nv_offset = 0x0;
|
||||
nv_size = fi.flash_size;
|
||||
req_blk_erase = !(fi.flash_flags & FLASH_FLAG_NOERASE);
|
||||
}
|
||||
|
||||
|
||||
/* Verify that the full NVRAM layout can be represented via size_t */
|
||||
if (nv_size > SIZE_MAX || SIZE_MAX - nv_size < nv_offset) {
|
||||
IOCFE_LOG(iocfe, "invalid NVRAM layout (%#x/%#jx)\n",
|
||||
nv_size, (intmax_t)nv_offset);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
iocfe->offset = nv_offset;
|
||||
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;
|
||||
|
||||
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;
|
||||
return (iocfe->size);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iocfe_setsize(struct bhnd_nvram_io *io, size_t size)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iocfe_read_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
const void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iocfe_write_ptr(struct bhnd_nvram_io *io, size_t offset,
|
||||
void **ptr, size_t nbytes, size_t *navail)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iocfe_write(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||
size_t nbytes)
|
||||
{
|
||||
/* unsupported */
|
||||
return (ENODEV);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_iocfe_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
|
||||
size_t nbytes)
|
||||
{
|
||||
struct bhnd_nvram_iocfe *iocfe;
|
||||
size_t remain;
|
||||
int64_t cfe_offset;
|
||||
int nr, nreq;
|
||||
|
||||
iocfe = (struct bhnd_nvram_iocfe *)io;
|
||||
|
||||
/* Determine (and validate) the base CFE offset */
|
||||
#if (SIZE_MAX > INT64_MAX)
|
||||
if (iocfe->offset > INT64_MAX || offset > INT64_MAX)
|
||||
return (ENXIO);
|
||||
#endif
|
||||
|
||||
if (INT64_MAX - offset < iocfe->offset)
|
||||
return (ENXIO);
|
||||
|
||||
cfe_offset = iocfe->offset + offset;
|
||||
|
||||
/* Verify that cfe_offset + nbytes is representable */
|
||||
if (INT64_MAX - cfe_offset < nbytes)
|
||||
return (ENXIO);
|
||||
|
||||
/* Perform the read */
|
||||
for (remain = nbytes; remain > 0;) {
|
||||
void *p;
|
||||
size_t nread;
|
||||
int64_t cfe_noff;
|
||||
|
||||
nread = (nbytes - remain);
|
||||
cfe_noff = cfe_offset + nread;
|
||||
p = ((uint8_t *)buffer + nread);
|
||||
nreq = ummin(INT_MAX, remain);
|
||||
|
||||
nr = cfe_readblk(iocfe->fd, cfe_noff, p, nreq);
|
||||
if (nr < 0) {
|
||||
IOCFE_LOG(iocfe, "cfe_readblk() failed: %d\n", nr);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Check for unexpected short read */
|
||||
if (nr == 0 && remain > 0) {
|
||||
/* If the request fits entirely within the CFE
|
||||
* device range, we shouldn't hit EOF */
|
||||
if (remain < iocfe->size &&
|
||||
iocfe->size - remain > offset)
|
||||
{
|
||||
IOCFE_LOG(iocfe, "cfe_readblk() returned "
|
||||
"unexpected short read (%d/%d)\n", nr,
|
||||
nreq);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
if (nr == 0)
|
||||
break;
|
||||
|
||||
remain -= nr;
|
||||
}
|
||||
|
||||
/* Check for short read */
|
||||
if (remain > 0)
|
||||
return (ENXIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t bhnd_nvram_cfe_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, bhnd_nvram_cfe_probe),
|
||||
DEVMETHOD(device_attach, bhnd_nvram_cfe_attach),
|
||||
DEVMETHOD(device_resume, bhnd_nvram_cfe_resume),
|
||||
DEVMETHOD(device_suspend, bhnd_nvram_cfe_suspend),
|
||||
DEVMETHOD(device_detach, bhnd_nvram_cfe_detach),
|
||||
|
||||
/* NVRAM interface */
|
||||
DEVMETHOD(bhnd_nvram_getvar, bhnd_nvram_cfe_getvar),
|
||||
DEVMETHOD(bhnd_nvram_setvar, bhnd_nvram_cfe_setvar),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(bhnd_nvram, bhnd_nvram_cfe, bhnd_nvram_cfe_methods,
|
||||
sizeof(struct bhnd_nvram_cfe_softc));
|
||||
EARLY_DRIVER_MODULE(bhnd_nvram_cfe, nexus, bhnd_nvram_cfe,
|
||||
bhnd_nvram_devclass, NULL, NULL, BUS_PASS_BUS + BUS_PASS_ORDER_EARLY);
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,36 +29,19 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _BHND_NVRAM_BHND_SPROM_PARSER_H_
|
||||
#define _BHND_NVRAM_BHND_SPROM_PARSER_H_
|
||||
#ifndef _MIPS_BROADCOM_BCM_NVRAM_CFE_H_
|
||||
#define _MIPS_BROADCOM_BCM_NVRAM_CFE_H_
|
||||
|
||||
#include <dev/bhnd/bhnd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
struct bhnd_sprom;
|
||||
#include <dev/bhnd/nvram/bhnd_nvram.h>
|
||||
#include <dev/bhnd/nvram/bhnd_nvram_store.h>
|
||||
|
||||
int bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
|
||||
bus_size_t offset);
|
||||
void bhnd_sprom_fini(struct bhnd_sprom *sprom);
|
||||
int bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
|
||||
size_t *len, bhnd_nvram_type type);
|
||||
int bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name,
|
||||
const void *buf, size_t len, bhnd_nvram_type type);
|
||||
|
||||
/**
|
||||
* bhnd sprom parser instance state.
|
||||
*/
|
||||
struct bhnd_sprom {
|
||||
device_t dev; /**< sprom parent device */
|
||||
|
||||
uint8_t sp_rev; /**< sprom revision */
|
||||
|
||||
struct bhnd_resource *sp_res; /**< sprom resource. */
|
||||
bus_size_t sp_res_off; /**< offset to sprom image */
|
||||
|
||||
uint8_t *sp_shadow; /**< sprom shadow */
|
||||
bus_size_t sp_size_max; /**< maximum possible sprom length */
|
||||
size_t sp_size; /**< shadow size */
|
||||
size_t sp_capacity; /**< shadow buffer capacity */
|
||||
/** bhnd_nvram_cfe driver instance state. */
|
||||
struct bhnd_nvram_cfe_softc {
|
||||
device_t dev;
|
||||
struct bhnd_nvram_store *store; /**< nvram store */
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_SPROM_PARSER_H_ */
|
||||
#endif /* _MIPS_BROADCOM_BCM_NVRAM_CFE_H_ */
|
@ -7,6 +7,8 @@
|
||||
mips/broadcom/bcm_machdep.c standard
|
||||
mips/broadcom/bcm_bmips.c optional siba_nexus siba
|
||||
mips/broadcom/bcm_mips74k.c optional bcma_nexus bcma
|
||||
mips/broadcom/bcm_nvram_cfe.c optional bhnd siba_nexus cfe | \
|
||||
bhnd bcma_nexus cfe
|
||||
mips/broadcom/bcm_pmu.c standard
|
||||
mips/mips/tick.c standard
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
#NO_UNIVERSE
|
||||
|
||||
ident JZ4780
|
||||
machine mips mipsel
|
||||
cpu CPU_XBURST
|
||||
|
@ -2,6 +2,8 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
#NO_UNIVERSE
|
||||
|
||||
ident X1000
|
||||
machine mips mipsel
|
||||
cpu CPU_XBURST
|
||||
|
@ -27,11 +27,21 @@ SRCS+= bhnd_pmu.c \
|
||||
SRCS+= bhnd_pmu_if.c bhnd_pmu_if.h
|
||||
|
||||
# NVRAM/SPROM
|
||||
SRCS+= bhnd_nvram.c \
|
||||
bhnd_nvram_parser.c \
|
||||
bhnd_sprom.c \
|
||||
bhnd_sprom_parser.c
|
||||
SRCS+= bhnd_nvram_common.c
|
||||
SRCS+= bhnd_nvram_data.c \
|
||||
bhnd_nvram_data_bcm.c \
|
||||
bhnd_nvram_data_bcmraw.c \
|
||||
bhnd_nvram_data_btxt.c \
|
||||
bhnd_nvram_data_sprom.c \
|
||||
bhnd_nvram_data_tlv.c \
|
||||
bhnd_nvram_io.c \
|
||||
bhnd_nvram_iobuf.c \
|
||||
bhnd_nvram_iores.c \
|
||||
bhnd_nvram_store.c \
|
||||
bhnd_nvram_subr.c \
|
||||
bhnd_nvram_value.c \
|
||||
bhnd_nvram_value_fmts.c \
|
||||
bhnd_nvram_value_prf.c \
|
||||
bhnd_sprom.c
|
||||
SRCS+= bhnd_nvram_map.h bhnd_nvram_map_data.h
|
||||
SRCS+= bhnd_nvram_if.c bhnd_nvram_if.h
|
||||
|
||||
|
@ -39,8 +39,10 @@
|
||||
#include <sys/param.h>
|
||||
#ifdef _KERNEL
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <netipsec/key_var.h>
|
||||
|
@ -1256,9 +1256,9 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
|
||||
*/
|
||||
mtu -= sizeof(struct ip6_hdr) - sizeof(struct ip);
|
||||
break;
|
||||
case ICMP6_TIME_EXCEED_TRANSIT:
|
||||
case ICMP6_TIME_EXCEEDED:
|
||||
type = ICMP_TIMXCEED;
|
||||
code = ICMP_TIMXCEED_INTRANS;
|
||||
code = icmp6->icmp6_code;
|
||||
break;
|
||||
case ICMP6_PARAM_PROB:
|
||||
switch (icmp6->icmp6_code) {
|
||||
|
@ -370,7 +370,8 @@ void __mnt_vnode_markerfree_active(struct vnode **mvp, struct mount *);
|
||||
#define MNTK_SUSPEND 0x08000000 /* request write suspension */
|
||||
#define MNTK_SUSPEND2 0x04000000 /* block secondary writes */
|
||||
#define MNTK_SUSPENDED 0x10000000 /* write operations are suspended */
|
||||
#define MNTK_UNUSED1 0x20000000
|
||||
#define MNTK_NULL_NOCACHE 0x20000000 /* auto disable cache for nullfs
|
||||
mounts over this fs */
|
||||
#define MNTK_LOOKUP_SHARED 0x40000000 /* FS supports shared lock lookups */
|
||||
#define MNTK_NOKNOTE 0x80000000 /* Don't send KNOTEs from VOP hooks */
|
||||
|
||||
|
@ -1512,19 +1512,17 @@ vm_page_alloc(vm_object_t object, vm_pindex_t pindex, int req)
|
||||
}
|
||||
|
||||
/*
|
||||
* The page allocation request can came from consumers which already
|
||||
* hold the free page queue mutex, like vm_page_insert() in
|
||||
* vm_page_cache().
|
||||
* Allocate a page if the number of free pages exceeds the minimum
|
||||
* for the request class.
|
||||
*/
|
||||
mtx_lock_flags(&vm_page_queue_free_mtx, MTX_RECURSE);
|
||||
mtx_lock(&vm_page_queue_free_mtx);
|
||||
if (vm_cnt.v_free_count > vm_cnt.v_free_reserved ||
|
||||
(req_class == VM_ALLOC_SYSTEM &&
|
||||
vm_cnt.v_free_count > vm_cnt.v_interrupt_free_min) ||
|
||||
(req_class == VM_ALLOC_INTERRUPT &&
|
||||
vm_cnt.v_free_count > 0)) {
|
||||
/*
|
||||
* Allocate from the free queue if the number of free pages
|
||||
* exceeds the minimum for the request class.
|
||||
* Can we allocate the page from a reservation?
|
||||
*/
|
||||
#if VM_NRESERVLEVEL > 0
|
||||
if (object == NULL || (object->flags & (OBJ_COLORED |
|
||||
@ -1532,6 +1530,9 @@ vm_page_alloc(vm_object_t object, vm_pindex_t pindex, int req)
|
||||
vm_reserv_alloc_page(object, pindex, mpred)) == NULL)
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* If not, allocate it from the free page queues.
|
||||
*/
|
||||
m = vm_phys_alloc_pages(object != NULL ?
|
||||
VM_FREEPOOL_DEFAULT : VM_FREEPOOL_DIRECT, 0);
|
||||
#if VM_NRESERVLEVEL > 0
|
||||
@ -1841,7 +1842,7 @@ vm_page_alloc_freelist(int flind, int req)
|
||||
/*
|
||||
* Do not allocate reserved pages unless the req has asked for it.
|
||||
*/
|
||||
mtx_lock_flags(&vm_page_queue_free_mtx, MTX_RECURSE);
|
||||
mtx_lock(&vm_page_queue_free_mtx);
|
||||
if (vm_cnt.v_free_count > vm_cnt.v_free_reserved ||
|
||||
(req_class == VM_ALLOC_SYSTEM &&
|
||||
vm_cnt.v_free_count > vm_cnt.v_interrupt_free_min) ||
|
||||
|
@ -478,8 +478,9 @@ native_lapic_init(vm_paddr_t addr)
|
||||
lapic_et.et_quality = 600;
|
||||
if (!arat) {
|
||||
lapic_et.et_flags |= ET_FLAGS_C3STOP;
|
||||
lapic_et.et_quality -= 200;
|
||||
} else if ((cpu_feature & CPUID_TSC) != 0 &&
|
||||
lapic_et.et_quality = 100;
|
||||
}
|
||||
if ((cpu_feature & CPUID_TSC) != 0 &&
|
||||
(cpu_feature2 & CPUID2_TSCDLT) != 0 &&
|
||||
tsc_is_invariant && tsc_freq != 0) {
|
||||
lapic_timer_tsc_deadline = 1;
|
||||
|
@ -1142,6 +1142,7 @@ OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/asan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/common_interface_defs.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/coverage_interface.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/dfsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/esan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/linux_syscall_hooks.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/lsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/msan_interface.h
|
||||
@ -1233,6 +1234,10 @@ OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.profile-i386.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.profile-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.safestack-i386.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.safestack-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats-i386.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats_client-i386.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
|
||||
|
@ -1635,7 +1635,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
|
||||
|
||||
bool device_tree::parse_define(const char *def)
|
||||
{
|
||||
char *val = strchr(def, '=');
|
||||
const char *val = strchr(def, '=');
|
||||
if (!val)
|
||||
{
|
||||
if (strlen(def) != 0)
|
||||
|
@ -68,22 +68,22 @@
|
||||
* leaf nodes count.
|
||||
*/
|
||||
typedef struct {
|
||||
int symbol_size; /* Size of the symbol table */
|
||||
int treelevels; /* Levels for the huffman tree */
|
||||
int symbol_size; /* Size of the symbol table */
|
||||
int treelevels; /* Levels for the huffman tree */
|
||||
|
||||
int *symbolsin; /* Table of leaf symbols count in
|
||||
each level */
|
||||
int *inodesin; /* Table of internal nodes count in
|
||||
each level */
|
||||
int *symbolsin; /* Table of leaf symbols count in each
|
||||
* level */
|
||||
int *inodesin; /* Table of internal nodes count in
|
||||
* each level */
|
||||
|
||||
char *symbol; /* The symbol table */
|
||||
char *symbol_eob; /* Pointer to the EOB symbol */
|
||||
char **tree; /* Decoding huffman tree (pointers to
|
||||
first symbol of each tree level */
|
||||
char *symbol; /* The symbol table */
|
||||
char *symbol_eob; /* Pointer to the EOB symbol */
|
||||
char **tree; /* Decoding huffman tree (pointers to
|
||||
* first symbol of each tree level */
|
||||
|
||||
off_t uncompressed_size; /* Uncompressed size */
|
||||
FILE *fpIn; /* Input stream */
|
||||
FILE *fpOut; /* Output stream */
|
||||
off_t uncompressed_size; /* Uncompressed size */
|
||||
FILE *fpIn; /* Input stream */
|
||||
FILE *fpOut; /* Output stream */
|
||||
} unpack_descriptor_t;
|
||||
|
||||
/*
|
||||
@ -122,7 +122,7 @@ unpackd_fill_inodesin(const unpack_descriptor_t *unpackd, int level)
|
||||
if (level < unpackd->treelevels) {
|
||||
unpackd_fill_inodesin(unpackd, level + 1);
|
||||
unpackd->inodesin[level] = (unpackd->inodesin[level + 1] +
|
||||
unpackd->symbolsin[level + 1]) / 2;
|
||||
unpackd->symbolsin[level + 1]) / 2;
|
||||
} else
|
||||
unpackd->inodesin[level] = 0;
|
||||
}
|
||||
@ -163,7 +163,7 @@ unpack_parse_header(int in, int out, char *pre, size_t prelen, off_t *bytes_in,
|
||||
|
||||
accepted_bytes(bytes_in, PACK_HEADER_LENGTH);
|
||||
|
||||
/* Obtain uncompressed length (bytes 2,3,4,5)*/
|
||||
/* Obtain uncompressed length (bytes 2,3,4,5) */
|
||||
unpackd->uncompressed_size = 0;
|
||||
for (i = 2; i <= 5; i++) {
|
||||
unpackd->uncompressed_size <<= 8;
|
||||
@ -187,7 +187,7 @@ unpack_parse_header(int in, int out, char *pre, size_t prelen, off_t *bytes_in,
|
||||
unpackd->symbolsin =
|
||||
calloc(unpackd->treelevels, sizeof(*(unpackd->symbolsin)));
|
||||
unpackd->tree =
|
||||
calloc(unpackd->treelevels, (sizeof (*(unpackd->tree))));
|
||||
calloc(unpackd->treelevels, (sizeof(*(unpackd->tree))));
|
||||
if (unpackd->inodesin == NULL || unpackd->symbolsin == NULL ||
|
||||
unpackd->tree == NULL)
|
||||
maybe_err("calloc");
|
||||
@ -196,7 +196,7 @@ unpack_parse_header(int in, int out, char *pre, size_t prelen, off_t *bytes_in,
|
||||
unpackd->treelevels--;
|
||||
|
||||
/* Read the levels symbol count table and calculate total */
|
||||
unpackd->symbol_size = 1; /* EOB */
|
||||
unpackd->symbol_size = 1; /* EOB */
|
||||
for (i = 0; i <= unpackd->treelevels; i++) {
|
||||
if ((thisbyte = fgetc(unpackd->fpIn)) == EOF)
|
||||
maybe_err("File appears to be truncated");
|
||||
@ -310,7 +310,7 @@ unpack_decode(const unpack_descriptor_t *unpackd, off_t *bytes_in)
|
||||
static off_t
|
||||
unpack(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
|
||||
{
|
||||
unpack_descriptor_t unpackd;
|
||||
unpack_descriptor_t unpackd;
|
||||
|
||||
in = dup(in);
|
||||
if (in == -1)
|
||||
@ -326,4 +326,3 @@ unpack(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
|
||||
/* If we reached here, the unpack was successful */
|
||||
return (unpackd.uncompressed_size);
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" From: @(#)nfsstat.1 8.1 (Berkeley) 6/6/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 13, 2016
|
||||
.Dd November 23, 2016
|
||||
.Dt NFSSTAT 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -38,7 +38,7 @@
|
||||
statistics
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl cdemszW
|
||||
.Op Fl cdEemszW
|
||||
.Op Fl M Ar core
|
||||
.Op Fl N Ar system
|
||||
.Op Fl w Ar wait
|
||||
@ -82,6 +82,16 @@ will increase by more than the measurement interval.
|
||||
.It Fl e
|
||||
Report the extra statistics collected by the NFS client and
|
||||
server for NFSv4.
|
||||
.It Fl E
|
||||
Similar to
|
||||
.Fl e
|
||||
except that the statistics include NFSv4.1 and the numbers aren't clipped
|
||||
at one billion.
|
||||
Only one of
|
||||
.Fl e
|
||||
or
|
||||
.Fl E
|
||||
can be specified.
|
||||
.It Fl M
|
||||
Extract values associated with the name list from the specified core
|
||||
instead of the default
|
||||
|
@ -113,6 +113,7 @@ static void usage(void);
|
||||
static char *sperc1(int, int);
|
||||
static char *sperc2(int, int);
|
||||
static void exp_intpr(int, int);
|
||||
static void exp41_intpr(int, int);
|
||||
static void exp_sidewaysintpr(u_int, int, int, int);
|
||||
static void compute_new_stats(struct nfsstatsv1 *cur_stats,
|
||||
struct nfsstatsv1 *prev_stats, int curop, long double etime,
|
||||
@ -155,7 +156,7 @@ main(int argc, char **argv)
|
||||
|
||||
interval = 0;
|
||||
memf = nlistf = NULL;
|
||||
while ((ch = getopt(argc, argv, "cdesWM:mN:w:z")) != -1)
|
||||
while ((ch = getopt(argc, argv, "cdEesWM:mN:w:z")) != -1)
|
||||
switch(ch) {
|
||||
case 'M':
|
||||
memf = optarg;
|
||||
@ -208,7 +209,14 @@ main(int argc, char **argv)
|
||||
case 'z':
|
||||
zflag = 1;
|
||||
break;
|
||||
case 'E':
|
||||
if (extra_output != 0)
|
||||
errx(1, "-e and -E are mutually exclusive");
|
||||
extra_output = 2;
|
||||
break;
|
||||
case 'e':
|
||||
if (extra_output != 0)
|
||||
errx(1, "-e and -E are mutually exclusive");
|
||||
extra_output = 1;
|
||||
break;
|
||||
case '?':
|
||||
@ -236,7 +244,9 @@ main(int argc, char **argv)
|
||||
exp_sidewaysintpr(interval, clientOnly, serverOnly,
|
||||
newStats);
|
||||
} else {
|
||||
if (extra_output != 0)
|
||||
if (extra_output == 2)
|
||||
exp41_intpr(clientOnly, serverOnly);
|
||||
else if (extra_output == 1)
|
||||
exp_intpr(clientOnly, serverOnly);
|
||||
else
|
||||
intpr(clientOnly, serverOnly);
|
||||
@ -795,6 +805,362 @@ exp_intpr(int clientOnly, int serverOnly)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a description of the nfs stats for the client/server,
|
||||
* including NFSv4.1.
|
||||
*/
|
||||
static void
|
||||
exp41_intpr(int clientOnly, int serverOnly)
|
||||
{
|
||||
int nfssvc_flag;
|
||||
|
||||
nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
|
||||
if (zflag != 0) {
|
||||
if (clientOnly != 0)
|
||||
nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
|
||||
if (serverOnly != 0)
|
||||
nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
|
||||
}
|
||||
ext_nfsstats.vers = NFSSTATS_V1;
|
||||
if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
|
||||
err(1, "Can't get stats");
|
||||
if (clientOnly != 0) {
|
||||
if (printtitle) {
|
||||
printf("Client Info:\n");
|
||||
printf("RPC Counts:\n");
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Getattr", "Setattr", "Lookup", "Readlink", "Read",
|
||||
"Write");
|
||||
}
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Create", "Remove", "Rename", "Link", "Symlink",
|
||||
"Mkdir");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Rmdir", "Readdir", "RdirPlus", "Access", "Mknod",
|
||||
"Fsstat");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Fsinfo", "PathConf", "Commit", "SetClId",
|
||||
"SetClIdCf", "Lock");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"LockT", "LockU", "Open", "OpenCfr", "OpenDownGr",
|
||||
"Close");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENDOWNGRADE],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CLOSE]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"RelLckOwn", "FreeStateID", "PutRootFH", "DelegRet",
|
||||
"GetACL", "SetACL");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RELEASELCKOWN],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FREESTATEID],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PUTROOTFH],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DELEGRETURN],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETACL],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETACL]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"ExchangeID", "CreateSess", "DestroySess",
|
||||
"DestroyClId", "LayoutGet", "GetDevInfo");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_EXCHANGEID],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATESESSION],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYSESSION],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYCLIENT],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTGET],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETDEVICEINFO]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"LayoutCommit", "LayoutReturn", "ReclaimCompl",
|
||||
"ReadDataS", "WriteDataS", "CommitDataS");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTCOMMIT],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTRETURN],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RECLAIMCOMPL],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDS],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITEDS],
|
||||
(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMITDS]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"OpenOwner", "Opens", "LockOwner", "Locks",
|
||||
"Delegs", "LocalOwn");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.clopenowners,
|
||||
(uintmax_t)ext_nfsstats.clopens,
|
||||
(uintmax_t)ext_nfsstats.cllockowners,
|
||||
(uintmax_t)ext_nfsstats.cllocks,
|
||||
(uintmax_t)ext_nfsstats.cldelegates,
|
||||
(uintmax_t)ext_nfsstats.cllocalopenowners);
|
||||
if (printtitle)
|
||||
printf("%12.12s %12.12s %12.12s\n",
|
||||
"LocalOpen", "LocalLOwn", "LocalLock");
|
||||
printf("%12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.cllocalopens,
|
||||
(uintmax_t)ext_nfsstats.cllocallockowners,
|
||||
(uintmax_t)ext_nfsstats.cllocallocks);
|
||||
if (printtitle) {
|
||||
printf("Rpc Info:\n");
|
||||
printf("%12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"TimedOut", "Invalid", "X Replies", "Retries",
|
||||
"Requests");
|
||||
}
|
||||
printf("%12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.rpctimeouts,
|
||||
(uintmax_t)ext_nfsstats.rpcinvalid,
|
||||
(uintmax_t)ext_nfsstats.rpcunexpected,
|
||||
(uintmax_t)ext_nfsstats.rpcretries,
|
||||
(uintmax_t)ext_nfsstats.rpcrequests);
|
||||
if (printtitle) {
|
||||
printf("Cache Info:\n");
|
||||
printf("%12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Attr Hits", "Misses", "Lkup Hits", "Misses");
|
||||
}
|
||||
printf("%12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.attrcache_hits,
|
||||
(uintmax_t)ext_nfsstats.attrcache_misses,
|
||||
(uintmax_t)ext_nfsstats.lookupcache_hits,
|
||||
(uintmax_t)ext_nfsstats.lookupcache_misses);
|
||||
if (printtitle)
|
||||
printf("%12.12s %12.12s %12.12s %12.12s\n",
|
||||
"BioR Hits", "Misses", "BioW Hits", "Misses");
|
||||
printf("%12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)(ext_nfsstats.biocache_reads -
|
||||
ext_nfsstats.read_bios),
|
||||
(uintmax_t)ext_nfsstats.read_bios,
|
||||
(uintmax_t)(ext_nfsstats.biocache_writes -
|
||||
ext_nfsstats.write_bios),
|
||||
(uintmax_t)ext_nfsstats.write_bios);
|
||||
if (printtitle)
|
||||
printf("%12.12s %12.12s %12.12s %12.12s\n",
|
||||
"BioRLHits", "Misses", "BioD Hits", "Misses");
|
||||
printf("%12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)(ext_nfsstats.biocache_readlinks -
|
||||
ext_nfsstats.readlink_bios),
|
||||
(uintmax_t)ext_nfsstats.readlink_bios,
|
||||
(uintmax_t)(ext_nfsstats.biocache_readdirs -
|
||||
ext_nfsstats.readdir_bios),
|
||||
(uintmax_t)ext_nfsstats.readdir_bios);
|
||||
if (printtitle)
|
||||
printf("%12.12s %12.12s\n", "DirE Hits", "Misses");
|
||||
printf("%12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.direofcache_hits,
|
||||
(uintmax_t)ext_nfsstats.direofcache_misses);
|
||||
}
|
||||
if (serverOnly != 0) {
|
||||
if (printtitle) {
|
||||
printf("\nServer Info:\n");
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Getattr", "Setattr", "Lookup", "Readlink",
|
||||
"Read", "Write");
|
||||
}
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Create", "Remove", "Rename", "Link", "Symlink",
|
||||
"Mkdir");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Rmdir", "Readdir", "RdirPlus", "Access", "Mknod",
|
||||
"Fsstat");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Fsinfo", "PathConf", "Commit", "LookupP",
|
||||
"SetClId", "SetClIdCf");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Open", "OpenAttr", "OpenDwnGr", "OpenCfrm",
|
||||
"DelePurge", "DeleRet");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"GetFH", "Lock", "LockT", "LockU", "Close",
|
||||
"Verify");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"NVerify", "PutFH", "PutPubFH", "PutRootFH",
|
||||
"Renew", "RestoreFH");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"SaveFH", "Secinfo", "RelLckOwn", "V4Create",
|
||||
"BackChannelCtrl", "BindConnToSess");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BACKCHANNELCTL],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BINDCONNTOSESS]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"ExchangeID", "CreateSess", "DestroySess",
|
||||
"FreeStateID", "GetDirDeleg", "GetDevInfo");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_EXCHANGEID],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATESESSION],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYSESSION],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FREESTATEID],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDIRDELEG],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVINFO]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"GetDevList", "LayoutCommit", "LayoutGet",
|
||||
"LayoutReturn", "SecInfNoName", "Sequence");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVLIST],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTCOMMIT],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTGET],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTRETURN],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFONONAME],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEQUENCE]);
|
||||
if (printtitle)
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"SetSSV", "TestStateID", "WantDeleg",
|
||||
"DestroyClID", "ReclaimCompl");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETSSV],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_TESTSTATEID],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WANTDELEG],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYCLIENTID],
|
||||
(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RECLAIMCOMPL]);
|
||||
if (printtitle) {
|
||||
printf("Server:\n");
|
||||
printf("%12.12s %12.12s %12.12s\n",
|
||||
"Retfailed", "Faults", "Clients");
|
||||
}
|
||||
printf("%12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srv_errs,
|
||||
(uintmax_t)ext_nfsstats.srvrpc_errs,
|
||||
(uintmax_t)ext_nfsstats.srvclients);
|
||||
if (printtitle)
|
||||
printf("%12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"OpenOwner", "Opens", "LockOwner",
|
||||
"Locks", "Delegs");
|
||||
printf("%12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvopenowners,
|
||||
(uintmax_t)ext_nfsstats.srvopens,
|
||||
(uintmax_t)ext_nfsstats.srvlockowners,
|
||||
(uintmax_t)ext_nfsstats.srvlocks,
|
||||
(uintmax_t)ext_nfsstats.srvdelegates);
|
||||
if (printtitle) {
|
||||
printf("Server Cache Stats:\n");
|
||||
printf(
|
||||
"%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
|
||||
"Inprog", "Idem", "Non-idem", "Misses",
|
||||
"CacheSize", "TCPPeak");
|
||||
}
|
||||
printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
|
||||
(uintmax_t)ext_nfsstats.srvcache_inproghits,
|
||||
(uintmax_t)ext_nfsstats.srvcache_idemdonehits,
|
||||
(uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
|
||||
(uintmax_t)ext_nfsstats.srvcache_misses,
|
||||
(uintmax_t)ext_nfsstats.srvcache_size,
|
||||
(uintmax_t)ext_nfsstats.srvcache_tcppeak);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compute_totals(struct nfsstatsv1 *total_stats, struct nfsstatsv1 *cur_stats)
|
||||
{
|
||||
|
@ -1070,7 +1070,7 @@ cd9660_rename_filename(cd9660node *iter, int num, int delete_chars)
|
||||
|
||||
tmp = malloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING);
|
||||
|
||||
while (i < num) {
|
||||
while (i < num && iter) {
|
||||
powers = 1;
|
||||
count = 0;
|
||||
digits = 1;
|
||||
|
@ -1835,6 +1835,7 @@ init(int signo)
|
||||
free((char *)f);
|
||||
}
|
||||
Files = NULL;
|
||||
*nextp = NULL;
|
||||
|
||||
/* open the configuration file */
|
||||
if ((cf = fopen(ConfFile, "r")) == NULL) {
|
||||
|
Loading…
Reference in New Issue
Block a user