Compare commits

...

30 Commits

Author SHA1 Message Date
Leah Rowe
58b17c98fd util/nvmutil: minor cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 18:25:24 +00:00
Leah Rowe
c8bd98c8a6 util/nvmutil: mem bound check on file read/write
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 18:17:07 +00:00
Leah Rowe
41f7f6352d util/nvmutil: rename gbe_bound for clarity
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:47:49 +00:00
Leah Rowe
b1abef8881 util/nvmutil: make defines easier to understand
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:44:07 +00:00
Leah Rowe
edca6c2cd3 util/nvmutil: tidy up set_mac_nib
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:35:00 +00:00
Leah Rowe
123e77d07f util/nvmutil: use portable printf on hexdump
lx means unsigned long, and row is size_t which often
is, but this is not guaranteed.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:31:04 +00:00
Leah Rowe
c0a77a7301 util/nvmutil: make the MAC shifting easier to read
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:22:31 +00:00
Leah Rowe
596643a0d5 util/nvmutil: optimise hextonum
there is 0x20 of different between a and A

so we can just or 0x20 and compare only lowercase.

we can also cast char (which may me signed on some
systems) to unsigned, and then only check whether
it's lower than 10.

this code results in far less branching (in C),
but a good optimising compiler probably wouldn't
have cared about the old version anyway.

it's just nicer C code.

this also means we no longer need to check for
X, only x.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:07:12 +00:00
Leah Rowe
6023d17b6e util/nvmutil: fix parenthesis warning in GCC
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 17:01:48 +00:00
Leah Rowe
199dbad96d util/nvmutil: tidy up set_mac_nib
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:55:23 +00:00
Leah Rowe
9e32456c8c util/nvmutil: clearer intent on struct data
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:52:02 +00:00
Leah Rowe
7ae2288c10 util/nvmutil: more readable NVM defines
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:49:41 +00:00
Leah Rowe
2f0c189da9 util/nvmutil: more readable SIZE_nKB defines
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:46:01 +00:00
Leah Rowe
7f6d7526cc util/nvmutil: use arc4random on DragonFly BSD
it has arc4random, so we will use it there.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:43:18 +00:00
Leah Rowe
a358a6fe09 util/nvmutil: use strlen instead of strnlen
strnlen isn't available on some older unices.

we already know the string will be null-terminated,
because it comes from argv, so runaway reads are
extremely unlikely (read: impossible).

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:41:59 +00:00
Leah Rowe
a82c766b8c util/nvmutil: add bound checks for gbe read/write
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:29:45 +00:00
Leah Rowe
94f5e70366 util/nvmutil: minor code cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 16:05:21 +00:00
Leah Rowe
0d4cc9e324 util/nvmutil: clearer macbuff init in set_mac_nib
and 1 does the same thing as mod 2, but it's cleaner.

i also now bitshift 3 times instead of times by 8,
which again is clearer in purpose.

i line breaked after h, to make it clear that all of
the next part is being shifted in

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 15:51:46 +00:00
Leah Rowe
7950a31c79 util/nvmutil: don't reset rfd on openbsd
it isn't defined there

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 15:02:46 +00:00
Leah Rowe
99543bc632 util/nvmutil: tidy up rhex()
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 14:59:35 +00:00
Leah Rowe
a4b9a333a9 util/nvmutil: properly handle sizeof in rhex()
sizeof is size_t, so we must act accordingly.

casting it to an int is unacceptable.

this version is also branchless.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 14:53:36 +00:00
Leah Rowe
cc47a756f2 util/nvmutil: make rmac an array, not a literal.
this prevents reassignment.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 14:42:57 +00:00
Leah Rowe
e7cbd9441c util/nvmutil: use arc4random when available
fall back to urandom.

also add a /dev/random fallback, for older unices.

with the posix compatibility changes, combined with
this change as above, the code should be portable
now. i expect it to compile on *many* unix systems!

pretty much everything from the last 30 years.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 14:42:29 +00:00
Leah Rowe
95b294db05 util/nvmutil: inline pos calculation on word()
we don't need a whole function. i previously did it
for clarity, but simply setting a variable all in
one line is totally fine.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:49:33 +00:00
Leah Rowe
d89d14e911 util/nvmutil: remove pointless check
the input is already size_t, which is unsigned

there's no point in checking for negative

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:37:38 +00:00
Leah Rowe
f96a119523 util/nvmutil: cast inside check_bound, not callers
the purpose of the cast is to check whether a given
integer would underflow under any circumstance.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:33:42 +00:00
Leah Rowe
a31236b1f8 util/nvmutil: comment regarding endianness
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:30:14 +00:00
Leah Rowe
c7409cce03 util/nvmutil: clean up set_word
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:28:51 +00:00
Leah Rowe
feee6a728f util/nvmutil: use size_t for offsets in words
size_t is generally the size of the address space, so
this is more reliable for our purposes; we're only
working on small buffers, but even so, it's a good
thing to do.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:28:04 +00:00
Leah Rowe
32429f2c37 util/nvmutil: remove the swap() function
directly handle swapping in word and set_word

in my testing, x86_64 and arm64 compilers actually produce
more efficient code this way. i previously only did a big
swap on the whole buffer on big-endian CPUs, and directly
accessed without swaps on little-endian, as an optimisation.

however, the old code is actually slower than what the
compiler produces, with the new code!

portability is retained with big-endian host CPUs and
little-endian host CPUs.

this also avoids the complication of memcpy and is just
generally extremely reliable by comparison.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-06 13:02:24 +00:00

View File

@@ -41,52 +41,104 @@ static void cmd_brick(void);
static void cmd_copy(void);
static void cmd_swap(void);
static int good_checksum(int);
static uint16_t word(int, int);
static void set_word(int, int, uint16_t);
static void check_bound(int, int);
static uint16_t word(size_t, int);
static void set_word(size_t, int, uint16_t);
static void check_bound(size_t, int);
static void write_gbe(void);
static void write_gbe_part(int);
static void swap(int);
static off_t gbe_file_offset(int, const char *);
static void *gbe_mem_offset(int p, const char *f_op);
static off_t gbe_x_offset(int, const char *, const char *, off_t, off_t);
static void usage(void);
static void err(int, const char *, ...);
static const char *getnvmprogname(void);
static void set_err(int);
/*
* On the platforms below, we will use arc4random
* for random MAC address generation.
*
* Later on, the code has fallbacks for other systems.
*/
#if defined(__OpenBSD__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__) || \
defined(__DragonFly__)
#ifndef HAVE_ARC4RANDOM
#define HAVE_ARC4RANDOM
#endif
#endif
/*
* Sizes in bytes:
*/
#define SIZE_1KB 1024
#define SIZE_4KB (4 * SIZE_1KB)
#define SIZE_8KB (8 * SIZE_1KB)
#define SIZE_16KB (16 * SIZE_1KB)
#define SIZE_128KB (128 * SIZE_1KB)
/*
* First 128 bytes of a GbE part contains
* the regular NVM (Non-Volatile-Memory)
* area. All of these bytes must add up,
* truncated to 0xBABA.
*
* The full GbE region is 4KB, but only
* the first 128 bytes are used here.
*
* There is a second 4KB part with the same
* rules, and it *should* be identical.
*/
#define GBE_FILE_SIZE SIZE_8KB /* for buf */
#define GBE_PART_SIZE (GBE_FILE_SIZE >> 1)
#define NVM_CHECKSUM 0xBABA
#define NVM_CHECKSUM_WORD 0x3F
#define NVM_SIZE 128
#define NVM_WORDS (NVM_SIZE >> 1)
#define NVM_CHECKSUM_WORD (NVM_WORDS - 1)
#define SIZE_4KB 0x1000
#define SIZE_8KB 0x2000
#define SIZE_16KB 0x4000
#define SIZE_128KB 0x20000
/*
* When reading files, we loop on error EINTR
* a maximum number of defined defined thus:
*/
#define MAX_RETRY_READ 30
/*
* Portably macro based on BSD nitems.
* Used to count the number of commands (see below).
*/
#define items(x) (sizeof((x)) / sizeof((x)[0]))
static uint8_t buf[SIZE_8KB];
static const char newrandom[] = "/dev/urandom";
static const char oldrandom[] = "/dev/random"; /* fallback on OLD unix */
#ifndef HAVE_ARC4RANDOM
static const char *rname = NULL;
#endif
static uint8_t buf[GBE_FILE_SIZE]; /* 8KB */
static uint16_t macbuf[3];
static off_t partsize;
static int flags;
#ifndef HAVE_ARC4RANDOM
static int rfd = -1;
#endif
static int fd = -1;
static struct stat st;
static int part;
static int invert;
static int part_modified[2];
static const char *mac = NULL;
static const char *rmac = "xx:xx:xx:xx:xx:xx";
static const char rmac[] = "xx:xx:xx:xx:xx:xx";
static const char *fname = "";
static const char *argv0;
struct op {
struct commands {
const char *str;
void (*cmd)(void);
int args;
};
static const struct op ops[] = {
static const struct commands command[] = {
{ "dump", cmd_dump, 3 },
{ "setmac", cmd_setmac, 3 },
{ "swap", cmd_swap, 3 },
@@ -110,8 +162,22 @@ main(int argc, char *argv[])
#ifdef __OpenBSD__
if (pledge("stdio rpath wpath unveil", NULL) == -1)
err(ECANCELED, "pledge");
/*
* For restricted filesystem access on early error.
*
* Unveiling the random device early, regardless of
* whether we will use it, prevents operations on any
* GbE files until we permit it, while performing the
* prerequisite error checks.
*
* We don't actually use the random device on platforms
* that have arc4random, which includes OpenBSD.
*/
if (unveil("/dev/urandom", "r") == -1)
err(ECANCELED, "unveil '/dev/urandom'");
if (unveil("/dev/random", "r") == -1)
err(ECANCELED, "unveil '/dev/random'");
#endif
set_cmd(argc, argv);
@@ -149,8 +215,10 @@ main(int argc, char *argv[])
if (close(fd) == -1)
err(ECANCELED, "close '%s'", fname);
#ifndef HAVE_ARC4RANDOM
if (close(rfd) == -1)
err(ECANCELED, "close '/dev/urandom'");
err(ECANCELED, "close '%s'", rname);
#endif
if (cmd != cmd_dump) {
if (errno)
@@ -180,7 +248,9 @@ reset_global_state(void)
fname = "";
cmd = NULL;
fd = -1;
#ifndef HAVE_ARC4RANDOM
rfd = -1;
#endif
part = 0;
memset(macbuf, 0, sizeof(macbuf));
@@ -197,28 +267,28 @@ set_cmd(int argc, char *argv[])
return;
}
for (i = 0; (i < items(ops)) && (cmd == NULL); i++) {
if (strcmp(argv[2], ops[i].str) != 0)
for (i = 0; i < items(command) && cmd == NULL; i++) {
if (strcmp(argv[2], command[i].str) != 0)
continue;
if (argc >= ops[i].args) {
cmd = ops[i].cmd;
if (argc >= command[i].args) {
cmd = command[i].cmd;
break;
}
err(EINVAL, "Too few args: command '%s'", ops[i].str);
err(EINVAL, "Too few args: command '%s'", command[i].str);
}
}
static void
check_cmd_args(int argc, char *argv[])
{
if ((cmd == NULL) && (argc > 2)) { /* nvm gbe [MAC] */
if (cmd == NULL && argc > 2) { /* nvm gbe [MAC] */
mac = argv[2];
cmd = cmd_setmac;
} else if (cmd == cmd_setmac) { /* nvm gbe setmac [MAC] */
mac = rmac; /* random MAC */
if (argc > 3)
mac = argv[3];
} else if ((cmd != NULL) && (argc > 3)) { /* user-supplied partnum */
} else if (cmd != NULL && argc > 3) { /* user-supplied partnum */
part = argv[3][0] - '0';
if (!((part == 0 || part == 1) && argv[3][1] == '\0'))
err(EINVAL, "Bad partnum: %s", argv[3]);
@@ -232,19 +302,27 @@ static void
set_io_flags(int argc, char *argv[])
{
flags = O_RDWR;
if (argc > 2) {
if (strcmp(argv[2], "dump") == 0)
flags = O_RDONLY;
}
if (argc < 3)
return;
if (strcmp(argv[2], "dump") == 0)
flags = O_RDONLY;
}
static void
open_files(void)
{
struct stat st;
#ifndef HAVE_ARC4RANDOM
struct stat st_rfd;
xopen(&rfd, "/dev/urandom", O_RDONLY, &st_rfd);
rname = newrandom;
if ((rfd = open(rname, O_RDONLY)) == -1) {
/*
* Fall back to /dev/random on old platforms
* where /dev/urandom does not exist.
*/
rname = oldrandom;
xopen(&rfd, rname, O_RDONLY, &st_rfd);
}
#endif
xopen(&fd, fname, flags, &st);
switch(st.st_size) {
@@ -274,15 +352,14 @@ read_gbe(void)
int p;
int do_read[2] = {1, 1};
if ((cmd == cmd_copy) || (cmd == cmd_brick) ||
(cmd == cmd_setchecksum))
if (cmd == cmd_copy || cmd == cmd_brick || cmd == cmd_setchecksum)
do_read[part ^ 1] = 0;
/*
* speedhack: if copy/swap, flip where data gets written to memory,
* so that cmd_copy and cmd_swap don't have to work on every word
*/
if ((cmd == cmd_copy) || (cmd == cmd_swap))
if (cmd == cmd_copy || cmd == cmd_swap)
invert = 1;
for (p = 0; p < 2; p++) {
@@ -294,10 +371,8 @@ read_gbe(void)
static void
read_gbe_part(int p, int invert)
{
read_file_PERFECTLY_or_die(fd, buf + (SIZE_4KB * (p ^ invert)),
SIZE_4KB, ((off_t)p) * partsize, fname, "pread");
swap(p ^ invert);
read_file_PERFECTLY_or_die(fd, gbe_mem_offset(p ^ invert, "pwrite"),
GBE_PART_SIZE, gbe_file_offset(p, "pread"), fname, "pread");
}
static void
@@ -320,7 +395,7 @@ parse_mac_string(void)
{
int mac_pos;
if (strnlen(mac, 20) != 17)
if (strlen(mac) != 17)
err(EINVAL, "MAC address is the wrong length");
for (mac_pos = 0; mac_pos < 16; mac_pos += 3)
@@ -359,52 +434,70 @@ static void
set_mac_nib(int mac_pos, int nib)
{
uint8_t h;
int byte = mac_pos / 3;
int byte;
int shift;
if ((h = hextonum(mac[mac_pos + nib])) > 15)
err(EINVAL, "Invalid character '%c'",
mac[mac_pos + nib]);
/* If random, ensure that local/unicast bits are set */
if ((byte == 0) && (nib == 1)) {
if ((mac[mac_pos + nib] == '?') ||
(mac[mac_pos + nib] == 'x') ||
(mac[mac_pos + nib] == 'X')) /* random */
h = (h & 0xE) | 2; /* local, unicast */
}
byte = mac_pos / 3;
macbuf[byte >> 1] |= (uint16_t)h << ((8 * (byte % 2)) +
(4 * (nib ^ 1)));
/* If random, ensure that local/unicast bits are set */
if ((byte == 0) && (nib == 1) &&
((mac[mac_pos + nib] == '?') ||
(mac[mac_pos + nib] == 'x') ||
(mac[mac_pos + nib] == 'X'))) /* random */
h = (h & 0xE) | 2; /* local, unicast */
/*
* The word is stored big-endian in the file.
* Logically in C, it is stored little-endian,
* because of how we load in read_gbe(), so
* we store the MAC address in reverse order
* per 2-byte word (there are 3 of these).
*/
shift = (byte & 1) << 3; /* left or right byte? */
shift |= (nib ^ 1) << 2; /* left or right nib? */
/*
* Now we can shift properly, OR'ing the result:
*/
macbuf[byte >> 1] |= (uint16_t)h << shift;
}
static uint8_t
hextonum(char ch)
{
if ((ch >= '0') && (ch <= '9'))
if ((unsigned)(ch - '0') <= 9)
return ch - '0';
else if ((ch >= 'A') && (ch <= 'F'))
return ch - 'A' + 10;
else if ((ch >= 'a') && (ch <= 'f'))
ch |= 0x20;
if ((unsigned)(ch - 'a') <= 5)
return ch - 'a' + 10;
else if ((ch == '?') || (ch == 'x') || (ch == 'X'))
return rhex(); /* random hex value */
else if (ch == '?' || ch == 'x')
return rhex(); /* random character */
else
return 16; /* error: invalid character */
return 16; /* invalid character */
}
static uint8_t
rhex(void)
{
static int n = -1;
static uint8_t rnum[12];
static size_t n = 0;
if (n == -1) {
n = sizeof(rnum) - 1;
read_file_PERFECTLY_or_die(rfd, rnum, sizeof(rnum),
0, "/dev/urandom", NULL);
if (!n) {
n = sizeof(rnum);
#ifdef HAVE_ARC4RANDOM
arc4random_buf(rnum, n);
#else
read_file_PERFECTLY_or_die(rfd, rnum, n, 0, rname, NULL);
#endif
}
return rnum[n--] & 0xf;
return rnum[--n] & 0xf;
}
static void
@@ -456,7 +549,7 @@ check_read_or_die(const char *rpath, ssize_t rval, size_t rsize,
static int
write_mac_part(int partnum)
{
int w;
size_t w;
part = partnum;
if (!good_checksum(partnum))
@@ -487,14 +580,14 @@ cmd_dump(void)
hexdump(partnum);
}
if ((num_invalid < 2))
if (num_invalid < 2)
errno = 0;
}
static void
print_mac_address(int partnum)
{
int c;
size_t c;
for (c = 0; c < 3; c++) {
uint16_t val16 = word(c, partnum);
printf("%02x:%02x", val16 & 0xff, val16 >> 8);
@@ -508,12 +601,12 @@ print_mac_address(int partnum)
static void
hexdump(int partnum)
{
int c;
int row;
size_t c;
size_t row;
uint16_t val16;
for (row = 0; row < 8; row++) {
printf("%08x ", row << 4);
printf("%08zx ", row << 4);
for (c = 0; c < 8; c++) {
val16 = word((row << 3) + c, partnum);
if (c == 4)
@@ -527,7 +620,7 @@ hexdump(int partnum)
static void
cmd_setchecksum(void)
{
int c;
size_t c;
uint16_t val16 = 0;
for (c = 0; c < NVM_CHECKSUM_WORD; c++)
@@ -596,7 +689,7 @@ cmd_swap(void)
static int
good_checksum(int partnum)
{
int w;
size_t w;
uint16_t total = 0;
for (w = 0; w <= NVM_CHECKSUM_WORD; w++)
total += word(w, partnum);
@@ -612,34 +705,37 @@ good_checksum(int partnum)
}
/*
* NOTE: memcpy is a bit sticky with host endianness,
* but we currently use it only when swap has
* been handled. just be careful about when the
* swap() function is called.
* GbE NVM files store 16-bit (2-byte) little-endian words.
* We must therefore swap the order when reading or writing.
*/
static uint16_t
word(int pos16, int p)
word(size_t pos16, int p)
{
uint16_t rval = 0;
size_t pos;
check_bound(pos16, p);
memcpy(&rval, buf + (SIZE_4KB * p) + (pos16 << 1), sizeof(uint16_t));
pos = (pos16 << 1) + ((size_t)p * GBE_PART_SIZE);
return rval;
return (uint16_t)buf[pos] | ((uint16_t)buf[pos + 1] << 8);
}
static void
set_word(int pos16, int p, uint16_t val16)
set_word(size_t pos16, int p, uint16_t val16)
{
size_t pos;
check_bound(pos16, p);
memcpy(buf + (SIZE_4KB * p) + (pos16 << 1), &val16, sizeof(uint16_t));
pos = (pos16 << 1) + ((size_t)p * GBE_PART_SIZE);
buf[pos] = (uint8_t)(val16 & 0xff);
buf[pos + 1] = (uint8_t)(val16 >> 8);
part_modified[p] = 1;
}
static void
check_bound(int c, int p)
check_bound(size_t c, int p)
{
/*
* NVM_SIZE assumed as the limit, because the
@@ -655,10 +751,10 @@ check_bound(int c, int p)
* we ever wish to work on the extented area.
*/
if ((p != 0) && (p != 1))
if (p != 0 && p != 1)
err(EINVAL, "check_bound: invalid partnum %d", p);
if ((c < 0) || (c >= (NVM_SIZE >> 1)))
err(EINVAL, "check_bound: out of bounds %d", c);
if (c >= NVM_WORDS)
err(EINVAL, "check_bound: out of bounds %zu", c);
}
static void
@@ -678,49 +774,61 @@ write_gbe(void)
static void
write_gbe_part(int p)
{
swap(p); /* swap bytes on big-endian host CPUs */
if (pwrite(fd, buf + (SIZE_4KB * p),
SIZE_4KB, (off_t)p * partsize) != (ssize_t)SIZE_4KB) {
if (pwrite(fd, gbe_mem_offset(p, "pwrite"),
GBE_PART_SIZE, gbe_file_offset(p, "pwrite")) != GBE_PART_SIZE) {
err(ECANCELED,
"Can't write %d b to '%s' p%d", SIZE_4KB, fname, p);
"Can't write %d b to '%s' p%d", GBE_PART_SIZE, fname, p);
}
}
/*
* GbE files store bytes in little-endian order.
* This function ensures big-endian host CPU support.
* Reads to GbE from write_gbe_part and read_gbe_part
* are filtered through here. These operations must
* only write from the 0th position or the half position
* within the GbE file, and write 4KB of data.
*
* This check is called, to ensure just that.
*/
static void
swap(int partnum)
static off_t
gbe_file_offset(int p, const char *f_op)
{
/*
* NVM_SIZE assumed as the limit; see notes in
* check_bound().
*
* TODO:
* This should be adjusted in the future, if
* we ever wish to work on the extended area.
*/
return gbe_x_offset(p, f_op, "file",
partsize, st.st_size);
}
size_t w;
size_t x;
/*
* This one is similar to gbe_file_offset,
* but used to check Gbe bounds in memory,
* and it is *also* used during file I/O.
*/
static void *
gbe_mem_offset(int p, const char *f_op)
{
off_t gbe_off = gbe_x_offset(p, f_op, "mem",
GBE_PART_SIZE, GBE_FILE_SIZE);
uint8_t *n = buf + (SIZE_4KB * partnum);
return (void *)(buf + gbe_off);
}
int e = 1;
if (*((uint8_t *)&e) == 1)
return; /* Little-endian host CPU; no swap needed. */
static off_t
gbe_x_offset(int p, const char *f_op, const char *d_type,
off_t nsize, off_t ncmp)
{
off_t off = (off_t)p * nsize;
/*
* The host CPU stores bytes in big-endian order.
* We will therefore reverse the order in memory:
*/
for (w = 0, x = 1; w < NVM_SIZE; w += 2, x += 2) {
uint8_t chg = n[w];
n[w] = n[x];
n[x] = chg;
}
if ((unsigned int)p > 1)
err(ECANCELED, "GbE %s %s invalid partnum: %s",
d_type, f_op, fname);
if (off + GBE_PART_SIZE > ncmp)
err(ECANCELED, "GbE %s %s out of bounds: %s",
d_type, f_op, fname);
if (off != 0 && off != ncmp >> 1)
err(ECANCELED, "GbE %s %s at bad offset: %s",
d_type, f_op, fname);
return off;
}
static void
@@ -770,10 +878,12 @@ getnvmprogname(void)
{
const char *p;
if ((argv0 == NULL) || (*argv0 == '\0'))
if (argv0 == NULL || *argv0 == '\0')
return "";
if ((p = strrchr(argv0, '/')))
p = strrchr(argv0, '/');
if (p)
return p + 1;
else
return argv0;