util/nvmutil: remove excessive comments
Signed-off-by: Leah Rowe <leah@libreboot.org>master
parent
e348ea0381
commit
d7312260e7
|
@ -25,9 +25,9 @@ uint8_t hextonum(char chs), rhex(void);
|
||||||
#define COMMAND argv[2]
|
#define COMMAND argv[2]
|
||||||
#define MAC_ADDRESS argv[3]
|
#define MAC_ADDRESS argv[3]
|
||||||
#define PARTN argv[3]
|
#define PARTN argv[3]
|
||||||
#define NVM_CHECKSUM 0xBABA /* checksum value */
|
#define NVM_CHECKSUM 0xBABA
|
||||||
#define NVM_CHECKSUM_WORD 0x3F /* checksum word position */
|
#define NVM_CHECKSUM_WORD 0x3F
|
||||||
#define NVM_SIZE 128 /* Area containing NVM words */
|
#define NVM_SIZE 128
|
||||||
|
|
||||||
#define SIZE_4KB 0x1000
|
#define SIZE_4KB 0x1000
|
||||||
#define SIZE_8KB 0x2000
|
#define SIZE_8KB 0x2000
|
||||||
|
@ -42,7 +42,6 @@ int flags, rfd, fd, part;
|
||||||
|
|
||||||
const char *strMac = NULL, *strRMac = "??:??:??:??:??:??", *filename = NULL;
|
const char *strMac = NULL, *strRMac = "??:??:??:??:??:??", *filename = NULL;
|
||||||
|
|
||||||
/* available commands, set a pointer based on user command */
|
|
||||||
typedef struct op {
|
typedef struct op {
|
||||||
char *str;
|
char *str;
|
||||||
void (*cmd)(void);
|
void (*cmd)(void);
|
||||||
|
@ -58,15 +57,12 @@ op_t op[] = {
|
||||||
};
|
};
|
||||||
void (*cmd)(void) = NULL;
|
void (*cmd)(void) = NULL;
|
||||||
|
|
||||||
/* wrappers for BSD-style err() function (error handling) */
|
|
||||||
#define ERR() errno = errno ? errno : ECANCELED
|
#define ERR() errno = errno ? errno : ECANCELED
|
||||||
#define err_if(x) if (x) err(ERR(), "%s", filename)
|
#define err_if(x) if (x) err(ERR(), "%s", filename)
|
||||||
|
|
||||||
/* Macro for opening a file with errors properly handled */
|
|
||||||
#define xopen(f,l,p) if ((f = open(l, p)) == -1) err(ERR(), "%s", l); \
|
#define xopen(f,l,p) if ((f = open(l, p)) == -1) err(ERR(), "%s", l); \
|
||||||
if (fstat(f, &st) == -1) err(ERR(), "%s", l)
|
if (fstat(f, &st) == -1) err(ERR(), "%s", l)
|
||||||
|
|
||||||
/* Macros for reading/writing the GbE file in memory */
|
|
||||||
#define word(pos16, partnum) ((uint16_t *) gbe[partnum])[pos16]
|
#define word(pos16, partnum) ((uint16_t *) gbe[partnum])[pos16]
|
||||||
#define setWord(pos16, p, val16) if (word(pos16, p) != val16) \
|
#define setWord(pos16, p, val16) if (word(pos16, p) != val16) \
|
||||||
nvmPartChanged[p] = 1 | (word(pos16, p) = val16)
|
nvmPartChanged[p] = 1 | (word(pos16, p) = val16)
|
||||||
|
@ -75,11 +71,10 @@ int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
/* OpenBSD pledge (sandboxing): https://man.openbsd.org/pledge.2 */
|
|
||||||
err_if(pledge("stdio rpath wpath unveil", NULL) == -1);
|
err_if(pledge("stdio rpath wpath unveil", NULL) == -1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (argc < 2) { /* TODO: manpage! */
|
if (argc < 2) {
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
err_if(pledge("stdio", NULL) == -1);
|
err_if(pledge("stdio", NULL) == -1);
|
||||||
#endif
|
#endif
|
||||||
|
@ -102,38 +97,32 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
if (strcmp(COMMAND, "dump") == 0) {
|
if (strcmp(COMMAND, "dump") == 0) {
|
||||||
flags = O_RDONLY; /* write not needed for dump cmd */
|
flags = O_RDONLY;
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
/* writes not needed for the dump command */
|
|
||||||
err_if(pledge("stdio rpath unveil", NULL) == -1);
|
err_if(pledge("stdio rpath unveil", NULL) == -1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for dir first, to prevent unveil from
|
|
||||||
permitting directory access on OpenBSD */
|
|
||||||
checkdir("/dev/urandom");
|
checkdir("/dev/urandom");
|
||||||
checkdir(filename); /* Must be a file, not a directory */
|
checkdir(filename);
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
/* OpenBSD unveil: https://man.openbsd.org/unveil.2 */
|
|
||||||
err_if(unveil("/dev/urandom", "r") == -1);
|
err_if(unveil("/dev/urandom", "r") == -1);
|
||||||
|
|
||||||
/* Only allow access to /dev/urandom and the gbe file */
|
if (flags == O_RDONLY) {
|
||||||
if (flags == O_RDONLY) { /* dump command */
|
err_if(unveil(filename, "r") == -1);
|
||||||
err_if(unveil(filename, "r") == -1); /* write not needed */
|
err_if(unveil(NULL, NULL) == -1);
|
||||||
err_if(unveil(NULL, NULL) == -1); /* lock unveil */
|
err_if(pledge("stdio rpath", NULL) == -1);
|
||||||
err_if(pledge("stdio rpath", NULL) == -1); /* lock unveil */
|
} else {
|
||||||
} else { /* other commands need read-write */
|
|
||||||
err_if(unveil(filename, "rw") == -1);
|
err_if(unveil(filename, "rw") == -1);
|
||||||
err_if(unveil(NULL, NULL) == -1); /* lock unveil */
|
err_if(unveil(NULL, NULL) == -1);
|
||||||
err_if(pledge("stdio rpath wpath", NULL) == -1); /* no unveil */
|
err_if(pledge("stdio rpath wpath", NULL) == -1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
openFiles(filename); /* open files first, to allow harder pledge: */
|
openFiles(filename);
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
/* OpenBSD sandboxing: https://man.openbsd.org/pledge.2 */
|
|
||||||
err_if(pledge("stdio", NULL) == -1);
|
err_if(pledge("stdio", NULL) == -1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -157,29 +146,22 @@ main(int argc, char *argv[])
|
||||||
cmd = cmd_setmac;
|
cmd = cmd_setmac;
|
||||||
} else if (cmd == cmd_setmac) { /* nvm gbe setmac [MAC] */
|
} else if (cmd == cmd_setmac) { /* nvm gbe setmac [MAC] */
|
||||||
strMac = strRMac; /* random MAC */
|
strMac = strRMac; /* random MAC */
|
||||||
if (argc > 3) /* user-supplied MAC (can be random) */
|
if (argc > 3)
|
||||||
strMac = MAC_ADDRESS;
|
strMac = MAC_ADDRESS;
|
||||||
} else if ((cmd != NULL) && (argc > 3)) { /* user-supplied partnum */
|
} else if ((cmd != NULL) && (argc > 3)) { /* user-supplied partnum */
|
||||||
err_if((errno = (!((part = PARTN[0] - '0') == 0 || part == 1))
|
err_if((errno = (!((part = PARTN[0] - '0') == 0 || part == 1))
|
||||||
|| PARTN[1] ? EINVAL : errno)); /* only allow '0' or '1' */
|
|| PARTN[1] ? EINVAL : errno)); /* only allow '0' or '1' */
|
||||||
}
|
}
|
||||||
err_if((errno = (cmd == NULL) ? EINVAL : errno)); /* bad user arg */
|
err_if((errno = (cmd == NULL) ? EINVAL : errno));
|
||||||
|
|
||||||
readGbe(); /* read gbe file into memory */
|
readGbe();
|
||||||
|
(*cmd)();
|
||||||
|
writeGbe();
|
||||||
|
|
||||||
(*cmd)(); /* operate on gbe file in memory */
|
err_if((errno != 0) && (cmd != cmd_dump));
|
||||||
|
return errno;
|
||||||
writeGbe(); /* write changes back to file */
|
|
||||||
|
|
||||||
err_if((errno != 0) && (cmd != cmd_dump)); /* don't err on dump */
|
|
||||||
return errno; /* errno can be set by the dump command */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* check whether urandom/file is a directory, and err if so,
|
|
||||||
* to prevent later unveil calls from permitting directory access
|
|
||||||
* on OpenBSD
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
checkdir(const char *path)
|
checkdir(const char *path)
|
||||||
{
|
{
|
||||||
|
@ -190,13 +172,12 @@ checkdir(const char *path)
|
||||||
err_if(errno);
|
err_if(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open gbe file and /dev/urandom, setting permissions */
|
|
||||||
void
|
void
|
||||||
openFiles(const char *path)
|
openFiles(const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
xopen(fd, path, flags); /* gbe file */
|
xopen(fd, path, flags);
|
||||||
|
|
||||||
switch(st.st_size) {
|
switch(st.st_size) {
|
||||||
case SIZE_8KB:
|
case SIZE_8KB:
|
||||||
|
@ -209,40 +190,32 @@ openFiles(const char *path)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the MAC address randomiser relies on reading urandom */
|
|
||||||
xopen(rfd, "/dev/urandom", O_RDONLY);
|
xopen(rfd, "/dev/urandom", O_RDONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read gbe file into memory buffer */
|
|
||||||
void
|
void
|
||||||
readGbe(void)
|
readGbe(void)
|
||||||
{
|
{
|
||||||
if ((cmd == cmd_swap) || (cmd == cmd_copy))
|
if ((cmd == cmd_swap) || (cmd == cmd_copy))
|
||||||
nf = SIZE_4KB; /* read/write the entire block */
|
nf = SIZE_4KB;
|
||||||
/* only need to do 4KB even on larger gbe files */
|
|
||||||
else
|
else
|
||||||
nf = NVM_SIZE; /* only read/write the nvm part of the block */
|
nf = NVM_SIZE;
|
||||||
|
|
||||||
if ((cmd == cmd_copy) || (cmd == cmd_setchecksum) || (cmd == cmd_brick))
|
if ((cmd == cmd_copy) || (cmd == cmd_setchecksum) || (cmd == cmd_brick))
|
||||||
do_read[part ^ 1] = 0; /* only read the user-specified part */
|
do_read[part ^ 1] = 0;
|
||||||
|
|
||||||
/* AND do_read[*] to avoid wasteful malloc */
|
|
||||||
/* cmd_copy also relies on this */
|
|
||||||
char *buf = malloc(nf << (do_read[0] & do_read[1]));
|
char *buf = malloc(nf << (do_read[0] & do_read[1]));
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
err(errno, NULL);
|
err(errno, NULL);
|
||||||
|
|
||||||
/* we pread per-part, so each part has its own pointer: */
|
|
||||||
/* if a do_read is 0, both pointers are the same; this accomplishes
|
|
||||||
the desired result for cmd_copy (see cmd_copy function) */
|
|
||||||
gbe[0] = (size_t) buf;
|
gbe[0] = (size_t) buf;
|
||||||
gbe[1] = gbe[0] + (nf * (do_read[0] & do_read[1]));
|
gbe[1] = gbe[0] + (nf * (do_read[0] & do_read[1]));
|
||||||
|
|
||||||
ssize_t tnr = 0; /* total bytes read */
|
ssize_t tnr = 0;
|
||||||
|
|
||||||
for (int p = 0; p < 2; p++) {
|
for (int p = 0; p < 2; p++) {
|
||||||
if (!do_read[p])
|
if (!do_read[p])
|
||||||
continue; /* avoid unnecessary reads */
|
continue;
|
||||||
|
|
||||||
ssize_t nr = pread(fd, (uint8_t *) gbe[p], nf, p * partsize);
|
ssize_t nr = pread(fd, (uint8_t *) gbe[p], nf, p * partsize);
|
||||||
err_if(nr == -1);
|
err_if(nr == -1);
|
||||||
|
@ -252,14 +225,12 @@ readGbe(void)
|
||||||
nr, filename, nf);
|
nr, filename, nf);
|
||||||
|
|
||||||
tnr += nr;
|
tnr += nr;
|
||||||
|
|
||||||
swap(p); /* handle big-endian host CPU */
|
swap(p); /* handle big-endian host CPU */
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%ld bytes read from file '%s'\n", tnr, filename);
|
printf("%ld bytes read from file '%s'\n", tnr, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set MAC address and checksum on nvm part */
|
|
||||||
void
|
void
|
||||||
cmd_setmac(void)
|
cmd_setmac(void)
|
||||||
{
|
{
|
||||||
|
@ -272,21 +243,20 @@ cmd_setmac(void)
|
||||||
if (!goodChecksum(part = partnum))
|
if (!goodChecksum(part = partnum))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int w = 0; w < 3; w++) /* write MAC to gbe part */
|
for (int w = 0; w < 3; w++)
|
||||||
setWord(w, partnum, mac[w]);
|
setWord(w, partnum, mac[w]);
|
||||||
|
|
||||||
printf("Wrote MAC address to part %d: ", partnum);
|
printf("Wrote MAC address to part %d: ", partnum);
|
||||||
macf(partnum);
|
macf(partnum);
|
||||||
|
|
||||||
cmd_setchecksum(); /* MAC updated; need valid checksum */
|
cmd_setchecksum();
|
||||||
mac_updated = 1;
|
mac_updated = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mac_updated)
|
if (mac_updated)
|
||||||
errno = 0; /* reset in case one of the checksums failed */
|
errno = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse MAC string, write to char buffer */
|
|
||||||
void
|
void
|
||||||
parseMacString(const char *strMac, uint16_t *mac)
|
parseMacString(const char *strMac, uint16_t *mac)
|
||||||
{
|
{
|
||||||
|
@ -303,14 +273,12 @@ parseMacString(const char *strMac, uint16_t *mac)
|
||||||
|
|
||||||
int byte = i / 3;
|
int byte = i / 3;
|
||||||
|
|
||||||
/* Update MAC buffer per-nibble from a given string */
|
|
||||||
for (int nib = 0; nib < 2; nib++, total += h) {
|
for (int nib = 0; nib < 2; nib++, total += h) {
|
||||||
if ((h = hextonum(strMac[i + nib])) > 15)
|
if ((h = hextonum(strMac[i + nib])) > 15)
|
||||||
err(errno = EINVAL, "Invalid character '%c'",
|
err(errno = EINVAL, "Invalid character '%c'",
|
||||||
strMac[i + nib]);
|
strMac[i + nib]);
|
||||||
|
|
||||||
/* if random: ensure local-only, unicast MAC */
|
if ((byte == 0) && (nib == 1))
|
||||||
if ((byte == 0) && (nib == 1)) /* unicast/local nib */
|
|
||||||
if (strMac[i + nib] == '?') /* ?=random */
|
if (strMac[i + nib] == '?') /* ?=random */
|
||||||
h = (h & 0xE) | 2; /* local, unicast */
|
h = (h & 0xE) | 2; /* local, unicast */
|
||||||
|
|
||||||
|
@ -325,7 +293,6 @@ parseMacString(const char *strMac, uint16_t *mac)
|
||||||
err(errno = EINVAL, "Invalid MAC (multicast bit set)");
|
err(errno = EINVAL, "Invalid MAC (multicast bit set)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert hex char to char value (0-15) */
|
|
||||||
uint8_t
|
uint8_t
|
||||||
hextonum(char ch)
|
hextonum(char ch)
|
||||||
{
|
{
|
||||||
|
@ -335,10 +302,9 @@ hextonum(char ch)
|
||||||
return ch - 'A' + 10;
|
return ch - 'A' + 10;
|
||||||
else if ((ch >= 'a') && (ch <= 'f'))
|
else if ((ch >= 'a') && (ch <= 'f'))
|
||||||
return ch - 'a' + 10;
|
return ch - 'a' + 10;
|
||||||
return (ch == '?') ? rhex() : 16; /* 16 for error (invalid char) */
|
return (ch == '?') ? rhex() : 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* random number generator */
|
|
||||||
uint8_t
|
uint8_t
|
||||||
rhex(void)
|
rhex(void)
|
||||||
{
|
{
|
||||||
|
@ -348,7 +314,6 @@ rhex(void)
|
||||||
return rnum[n--] & 0xf;
|
return rnum[n--] & 0xf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print mac address and hexdump of parts */
|
|
||||||
void
|
void
|
||||||
cmd_dump(void)
|
cmd_dump(void)
|
||||||
{
|
{
|
||||||
|
@ -369,7 +334,6 @@ cmd_dump(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print mac address of part */
|
|
||||||
void
|
void
|
||||||
macf(int partnum)
|
macf(int partnum)
|
||||||
{
|
{
|
||||||
|
@ -383,7 +347,6 @@ macf(int partnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print hexdump of nvm part */
|
|
||||||
void
|
void
|
||||||
hexdump(int partnum)
|
hexdump(int partnum)
|
||||||
{
|
{
|
||||||
|
@ -399,7 +362,6 @@ hexdump(int partnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* correct the checksum on part */
|
|
||||||
void
|
void
|
||||||
cmd_setchecksum(void)
|
cmd_setchecksum(void)
|
||||||
{
|
{
|
||||||
|
@ -407,11 +369,9 @@ cmd_setchecksum(void)
|
||||||
for (int c = 0; c < NVM_CHECKSUM_WORD; c++)
|
for (int c = 0; c < NVM_CHECKSUM_WORD; c++)
|
||||||
val16 += word(c, part);
|
val16 += word(c, part);
|
||||||
|
|
||||||
/* correct the checksum */
|
|
||||||
setWord(NVM_CHECKSUM_WORD, part, NVM_CHECKSUM - val16);
|
setWord(NVM_CHECKSUM_WORD, part, NVM_CHECKSUM - val16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* intentionally set wrong checksum on part */
|
|
||||||
void
|
void
|
||||||
cmd_brick(void)
|
cmd_brick(void)
|
||||||
{
|
{
|
||||||
|
@ -420,23 +380,17 @@ cmd_brick(void)
|
||||||
((word(NVM_CHECKSUM_WORD, part)) ^ 0xFF));
|
((word(NVM_CHECKSUM_WORD, part)) ^ 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* overwrite the contents of one part with the other */
|
|
||||||
void
|
void
|
||||||
cmd_copy(void)
|
cmd_copy(void)
|
||||||
{
|
{
|
||||||
nvmPartChanged[part ^ 1] = goodChecksum(part);
|
nvmPartChanged[part ^ 1] = goodChecksum(part);
|
||||||
|
|
||||||
/* no need to actually copy because gbe[] pointers are both the same */
|
|
||||||
/* we simply set the right nvm part as changed, and write the file */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* swap contents between the two parts */
|
|
||||||
void
|
void
|
||||||
cmd_swap(void) {
|
cmd_swap(void) {
|
||||||
err_if(!(goodChecksum(0) || goodChecksum(1)));
|
err_if(!(goodChecksum(0) || goodChecksum(1)));
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
/* speedhack: swap pointers, not words. (xor swap) */
|
|
||||||
gbe[0] ^= gbe[1];
|
gbe[0] ^= gbe[1];
|
||||||
gbe[1] ^= gbe[0];
|
gbe[1] ^= gbe[0];
|
||||||
gbe[0] ^= gbe[1];
|
gbe[0] ^= gbe[1];
|
||||||
|
@ -444,7 +398,6 @@ cmd_swap(void) {
|
||||||
nvmPartChanged[0] = nvmPartChanged[1] = 1;
|
nvmPartChanged[0] = nvmPartChanged[1] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify nvm part checksum (return 1 if valid) */
|
|
||||||
int
|
int
|
||||||
goodChecksum(int partnum)
|
goodChecksum(int partnum)
|
||||||
{
|
{
|
||||||
|
@ -460,11 +413,10 @@ goodChecksum(int partnum)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write the nvm parts back to the file */
|
|
||||||
void
|
void
|
||||||
writeGbe(void)
|
writeGbe(void)
|
||||||
{
|
{
|
||||||
ssize_t tnw = 0; /* total bytes written */
|
ssize_t tnw = 0;
|
||||||
|
|
||||||
for (int p = 0; p < 2; p++) {
|
for (int p = 0; p < 2; p++) {
|
||||||
if ((!nvmPartChanged[p]) || (flags == O_RDONLY))
|
if ((!nvmPartChanged[p]) || (flags == O_RDONLY))
|
||||||
|
@ -498,10 +450,9 @@ writeGbe(void)
|
||||||
err_if(close(fd) == -1);
|
err_if(close(fd) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* swap byte order on big-endian CPUs. swap skipped on little endian */
|
|
||||||
void
|
void
|
||||||
swap(int partnum) /* swaps bytes in words, not pointers. */
|
swap(int partnum)
|
||||||
{ /* not to be confused with cmd_swap */
|
{
|
||||||
size_t w, x;
|
size_t w, x;
|
||||||
uint8_t *n = (uint8_t *) gbe[partnum];
|
uint8_t *n = (uint8_t *) gbe[partnum];
|
||||||
int e = 1;
|
int e = 1;
|
||||||
|
|
Loading…
Reference in New Issue