summaryrefslogtreecommitdiff
path: root/util/nvmutil/nvmutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/nvmutil/nvmutil.c')
-rw-r--r--util/nvmutil/nvmutil.c304
1 files changed, 79 insertions, 225 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index a489dd8d..2af10373 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -1,180 +1,76 @@
-/*
- * Copyright (C) 2022, 2023 Leah Rowe <info@minifree.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
+/* Copyright (c) 2022, 2023 Leah Rowe <info@minifree.org> */
+/* SPDX-License-Identifier: MIT */
-/*
- * This file is part of Libreboot. See:
- * https://libreboot.org/docs/install/nvmutil.html
- */
-
-#include <sys/stat.h>
-
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-void readGbeFile(int *fd, const char *path, int flags,
- size_t nr);
-void cmd_setmac(const char *strMac);
-int invalidMacAddress(const char *strMac, uint16_t *mac);
-uint8_t hextonum(char chs);
-uint8_t rhex(void);
-void cmd_dump(void);
-void showmac(int partnum);
-void hexdump(int partnum);
-void cmd_setchecksum(void);
-void cmd_brick(void);
-void cmd_swap(void);
-void cmd_copy(void);
-int validChecksum(int partnum);
-uint16_t word(int pos16, int partnum);
-void setWord(int pos16, int partnum, uint16_t val16);
-void byteswap(int n, int partnum);
-void writeGbeFile(int *fd, const char *filename, size_t nw);
-
-#define FILENAME argv[1]
-#define COMMAND argv[2]
-#define MAC_ADDRESS argv[3]
-#define PARTNUM argv[3]
-#define SIZE_4KB 0x1000
-#define SIZE_8KB 0x2000
-
-uint16_t buf16[SIZE_4KB];
-uint8_t *buf;
-size_t gbe[2];
-uint8_t skipread[2] = {0, 0};
-
-int part, gbeFileModified = 0;
-uint8_t nvmPartModified[2] = {0, 0};
-
-uint16_t test;
-uint8_t big_endian;
+#include "nvmutil.h"
int
main(int argc, char *argv[])
{
- size_t nr = 128;
- int fd, flags = O_RDWR;
- void (*cmd)(void) = NULL;
- const char *strMac = NULL, *strRMac = "??:??:??:??:??:??";
-
-#ifdef HAVE_PLEDGE /* openbsd */
- if (pledge("stdio wpath", NULL) == -1)
- err(errno, "pledge");
-#endif
-
- buf = (uint8_t *) &buf16;
- gbe[1] = (gbe[0] = (size_t) buf) + SIZE_4KB;
-
- test = 1;
- big_endian = ((uint8_t *) &test)[0] ^ 1;
-
- if (argc == 3) {
- if (strcmp(COMMAND, "dump") == 0) {
-#ifdef HAVE_PLEDGE /* openbsd */
- if (pledge("stdio rpath", NULL) == -1)
- err(errno, "pledge");
-#endif
- flags = O_RDONLY;
- cmd = &cmd_dump;
- } else if (strcmp(COMMAND, "setmac") == 0) {
- strMac = (char *) strRMac; /* random mac address */
- } else if (strcmp(COMMAND, "swap") == 0) {
- cmd = &cmd_swap;
- nr = SIZE_4KB;
- }
- } else if (argc == 4) {
- if (strcmp(COMMAND, "setmac") == 0) {
- strMac = MAC_ADDRESS; /* user-supplied mac address */
- } else if ((!((part = PARTNUM[0] - '0') == 0 || part == 1))
- || PARTNUM[1]) { /* only allow '1' or '0' */
- errno = EINVAL;
- } else if (strcmp(COMMAND, "setchecksum") == 0) {
- cmd = &cmd_setchecksum;
- } else if (strcmp(COMMAND, "brick") == 0) {
- cmd = &cmd_brick;
- } else if (strcmp(COMMAND, "copy") == 0) {
- cmd = &cmd_copy;
- nr = SIZE_4KB;
- }
+ xpledge("stdio rpath wpath unveil", NULL);
+ xunveil("/dev/urandom", "r");
+ err_if((errno = argc < 3 ? EINVAL : errno));
+ if ((flags = (strcmp(COMMAND, "dump") == 0) ? O_RDONLY : flags)
+ == O_RDONLY) {
+ xunveil(FILENAME, "r");
+ xpledge("stdio rpath", NULL);
+ } else {
+ xunveil(FILENAME, "rw");
+ xpledge("stdio rpath wpath", NULL);
}
-
- if ((strMac == NULL) && (cmd == NULL))
- errno = EINVAL;
-
- if (errno == 0) {
- skipread[part ^ 1] = (cmd == &cmd_copy) |
- (cmd == &cmd_setchecksum) | (cmd == &cmd_brick);
- readGbeFile(&fd, FILENAME, flags, nr);
- if (strMac != NULL)
- cmd_setmac(strMac); /* nvm gbe.bin setmac */
- else if (cmd != NULL)
- (*cmd)(); /* all other commands except setmac */
- writeGbeFile(&fd, FILENAME, nr);
- }
-
- if ((errno != 0) && (cmd != &cmd_dump))
- err(errno, NULL);
+ openFiles(FILENAME);
+ xpledge("stdio", NULL);
+
+ for (int i = 0; i < 6; i++)
+ if (strcmp(COMMAND, op[i].str) == 0)
+ if ((cmd = argc >= op[i].args ? op[i].cmd : NULL))
+ break;
+ if (cmd == cmd_setmac)
+ strMac = (argc > 3) ? MAC_ADDRESS : strRMac;
+ else if ((cmd != NULL) && (argc > 3))
+ err_if((errno = (!((part = PARTNUM[0] - '0') == 0 || part == 1))
+ || PARTNUM[1] ? EINVAL : errno));
+ err_if((errno = (cmd == NULL) ? EINVAL : errno));
+
+ readGbeFile(FILENAME);
+ (*cmd)();
+
+ if ((gbeFileModified) && (flags != O_RDONLY))
+ writeGbeFile(FILENAME);
+ err_if((errno != 0) && (cmd != &cmd_dump));
return errno;
}
void
-readGbeFile(int *fd, const char *path, int flags, size_t nr)
+openFiles(const char *path)
{
struct stat st;
- if (opendir(path) != NULL)
- err(errno = EISDIR, "%s", path);
- else if (((*fd) = open(path, flags)) == -1)
- err(errno, "%s", path);
- else if (fstat((*fd), &st) == -1)
- err(errno, "%s", path);
- else if ((st.st_size != SIZE_8KB))
+ xopen(fd, path, flags);
+ if ((st.st_size != SIZE_8KB))
err(errno = ECANCELED, "File `%s` not 8KiB", path);
- else if (errno == ENOTDIR)
- errno = 0;
+ xopen(rfd, "/dev/urandom", O_RDONLY);
+ errno = errno != ENOTDIR ? errno : 0;
+}
+void
+readGbeFile(const char *path)
+{
+ nf = ((cmd == cmd_swap) || (cmd == cmd_copy)) ? SIZE_4KB : nf;
+ skipread[part ^ 1] = (cmd == &cmd_copy) | (cmd == &cmd_setchecksum)
+ | (cmd == &cmd_brick);
+ gbe[1] = (gbe[0] = (size_t) buf) + SIZE_4KB;
for (int p = 0; p < 2; p++) {
if (skipread[p])
continue;
- if (pread((*fd), (uint8_t *) gbe[p], nr, p << 12) == -1)
- err(errno, "%s", path);
- if (big_endian)
- byteswap(nr, p);
+ xpread(fd, (uint8_t *) gbe[p], nf, p << 12, path);
+ handle_endianness(p);
}
}
void
-cmd_setmac(const char *strMac)
+cmd_setmac(void)
{
- uint16_t mac[3] = {0, 0, 0};
if (invalidMacAddress(strMac, mac))
err(errno = ECANCELED, "Bad MAC address");
-
for (int partnum = 0; partnum < 2; partnum++) {
if (validChecksum(part = partnum)) {
for (int w = 0; w < 3; w++)
@@ -187,10 +83,9 @@ cmd_setmac(const char *strMac)
int
invalidMacAddress(const char *strMac, uint16_t *mac)
{
- uint8_t h;
uint64_t total = 0;
if (strnlen(strMac, 20) == 17) {
- for (int i = 0; i < 16; i += 3) {
+ for (uint8_t h, i = 0; i < 16; i += 3) {
if (i != 15)
if (strMac[i + 2] != ':')
return 1;
@@ -202,7 +97,7 @@ invalidMacAddress(const char *strMac, uint16_t *mac)
if (strMac[i + nib] == '?')
h = (h & 0xE) | 2; /* local, unicast */
mac[byte >> 1] |= ((uint16_t ) h)
- << ((8 * (byte % 2)) + (4 * (nib ^ 1)));
+ << ((8 * (byte % 2)) + (4 * (nib ^ 1)));
}
}}
return ((total == 0) | (mac[0] & 1)); /* multicast/all-zero banned */
@@ -217,50 +112,35 @@ hextonum(char ch)
return ch - 'A' + 10;
else if ((ch >= 'a') && (ch <= 'f'))
return ch - 'a' + 10;
- else if (ch == '?')
- return rhex(); /* random number */
- else
- return 16;
+ return (ch == '?') ? rhex() : 16;
}
uint8_t
rhex(void)
{
- static int rfd = -1;
- static uint64_t rnum = 0;
- if (rnum == 0) {
- if (rfd == -1)
- if ((rfd = open("/dev/urandom", O_RDONLY)) == -1)
- err(errno, "/dev/urandom");
- if (read(rfd, (uint8_t *) &rnum, 8) == -1)
- err(errno, "/dev/urandom");
- }
- uint8_t rval = (uint8_t) (rnum & 0xf);
- rnum >>= 4;
- return rval;
+ static uint8_t n = 0, rnum[16];
+ if (!n)
+ xpread(rfd, (uint8_t *) &rnum, (n = 15) + 1, 0, "/dev/urandom");
+ return rnum[n--] & 0xf;
}
void
cmd_dump(void)
{
- int partnum, numInvalid = 0;
- for (partnum = 0; partnum < 2; partnum++) {
+ for (int partnum = 0, numInvalid = 0; partnum < 2; partnum++) {
if (!validChecksum(partnum))
++numInvalid;
printf("MAC (part %d): ", partnum);
- showmac(partnum);
- hexdump(partnum);
+ showmac(partnum), hexdump(partnum);
+ errno = ((numInvalid < 2) && (partnum)) ? 0 : errno;
}
- if (numInvalid < 2)
- errno = 0;
}
void
showmac(int partnum)
{
- uint16_t val16;
for (int c = 0; c < 3; c++) {
- val16 = word(c, partnum);
+ uint16_t val16 = word(c, partnum);
printf("%02x:%02x", val16 & 0xff, val16 >> 8);
printf(c == 2 ? "\n" : ":");
}
@@ -274,8 +154,7 @@ hexdump(int partnum)
for (int c = 0; c < 8; c++) {
uint16_t val16 = word((row << 3) + c, partnum);
printf(" %02x%02x", val16 >> 8, val16 & 0xff);
- }
- printf("\n");
+ } printf("\n");
}
}
@@ -298,18 +177,16 @@ cmd_brick(void)
void
cmd_swap(void)
{
- gbe[0] ^= gbe[1]; /* speedhack: swap ptr, not words */
- gbe[1] ^= gbe[0];
- gbe[0] ^= gbe[1];
- gbeFileModified = nvmPartModified[0] = nvmPartModified[1]
- = validChecksum(1) | validChecksum(0);
+ if ((gbeFileModified = nvmPartModified[0] = nvmPartModified[1]
+ = validChecksum(1) | validChecksum(0)))
+ xorswap(gbe[0], gbe[1]); /* speedhack: swap ptr, not words */
}
void
cmd_copy(void)
{
- gbe[part ^ 1] = gbe[part]; /* speedhack: copy ptr, not words */
- gbeFileModified = nvmPartModified[part ^ 1] = validChecksum(part);
+ if ((gbeFileModified = nvmPartModified[part ^ 1] = validChecksum(part)))
+ gbe[part ^ 1] = gbe[part]; /* speedhack: copy ptr, not words */
}
int
@@ -324,53 +201,30 @@ validChecksum(int partnum)
return (errno = ECANCELED) & 0;
}
-uint16_t
-word(int pos16, int partnum)
-{
- return buf16[pos16 + (partnum << 11)];
-}
-
void
setWord(int pos16, int partnum, uint16_t val16)
{
- gbeFileModified = 1;
- if (word(pos16, partnum) == val16)
- return;
- buf16[pos16 + (partnum << 11)] = val16;
- nvmPartModified[partnum] = 1;
+ if ((gbeFileModified = 1) && word(pos16, partnum) != val16)
+ nvmPartModified[partnum] = 1 | (word(pos16, partnum) = val16);
}
void
-byteswap(int n, int partnum)
+xorswap_buf(int partnum)
{
- int b1, b2, wcount = n >> 1;
uint8_t *nbuf = (uint8_t *) gbe[partnum];
- for (int w = 0; w < wcount; w++) {
- b1 = b2 = w << 1;
- nbuf[b1] ^= nbuf[++b2]; /* xor swap */
- nbuf[b2] ^= nbuf[b1];
- nbuf[b1] ^= nbuf[b2];
- }
+ for (size_t w = 0; w < (nf >> 1); w++)
+ xorswap(nbuf[w << 1], nbuf[(w << 1) + 1]);
}
void
-writeGbeFile(int *fd, const char *filename, size_t nw)
+writeGbeFile(const char *filename)
{
- if (gbeFileModified)
- errno = 0;
- for (int p = 0; p < 2; p++) {
- if (gbe[0] > gbe[1])
- p ^= 1; /* speedhack: write sequentially on-disk */
- if (!nvmPartModified[p])
- goto next_part;
- if (big_endian)
- byteswap(nw, p);
- if (pwrite((*fd), (uint8_t *) gbe[p], nw, p << 12) == -1)
- err(errno, "%s", filename);
-next_part:
- if (gbe[0] > gbe[1])
- p ^= 1; /* speedhack: write sequentially on-disk */
+ errno = 0;
+ for (int x = gbe[0] > gbe[1] ? 1 : 0, p = 0; p < 2; p++, x ^= 1) {
+ if (!nvmPartModified[x])
+ continue;
+ handle_endianness(x);
+ xpwrite(fd, (uint8_t *) gbe[x], nf, x << 12, filename);
}
- if (close((*fd)))
- err(errno, "%s", filename);
+ xclose(fd, filename);
}