summaryrefslogtreecommitdiff
path: root/util/nvmutil/command.c
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-18 14:04:51 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-18 14:20:06 +0000
commit594cc262f4404feab6ab437dacc010f6d1f6263f (patch)
tree6f3fc0157fbfbf8bb98216703246f888cf59cfbc /util/nvmutil/command.c
parent4dbb1c9bf3e88612ccaf471d3f6db120d255b33b (diff)
nvmutil: move lib files to lib/
only keep nvmutil.c in main Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util/nvmutil/command.c')
-rw-r--r--util/nvmutil/command.c603
1 files changed, 0 insertions, 603 deletions
diff --git a/util/nvmutil/command.c b/util/nvmutil/command.c
deleted file mode 100644
index e04f3098..00000000
--- a/util/nvmutil/command.c
+++ /dev/null
@@ -1,603 +0,0 @@
-/* SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
- *
- * Command handlers for nvmutil
- */
-
-#ifdef __OpenBSD__
-#include <sys/param.h>
-#endif
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "include/common.h"
-
-/*
- * Guard against regressions by maintainers (command table)
- */
-void
-sanitize_command_list(void)
-{
- struct xstate *x = xstatus();
-
- unsigned long c;
- unsigned long num_commands;
-
- num_commands = items(x->cmd);
-
- for (c = 0; c < num_commands; c++)
- sanitize_command_index(c);
-}
-
-/*
- * TODO: specific config checks per command
- */
-void
-sanitize_command_index(unsigned long c)
-{
- struct xstate *x = xstatus();
- struct commands *cmd;
-
- int _flag;
- unsigned long gbe_rw_size;
-
- cmd = &x->cmd[c];
-
- check_command_num(c);
-
- if (cmd->argc < 3)
- err(EINVAL, "cmd index %lu: argc below 3, %d",
- (unsigned long)c, cmd->argc);
-
- if (cmd->str == NULL)
- err(EINVAL, "cmd index %lu: NULL str",
- (unsigned long)c);
-
- if (*cmd->str == '\0')
- err(EINVAL, "cmd index %lu: empty str",
- (unsigned long)c);
-
- if (xstrxlen(cmd->str, MAX_CMD_LEN + 1) >
- MAX_CMD_LEN) {
- err(EINVAL, "cmd index %lu: str too long: %s",
- (unsigned long)c, cmd->str);
- }
-
- if (cmd->run == NULL)
- err(EINVAL, "cmd index %lu: cmd ptr null",
- (unsigned long)c);
-
- check_bin(cmd->arg_part, "cmd.arg_part");
- check_bin(cmd->chksum_read, "cmd.chksum_read");
- check_bin(cmd->chksum_write, "cmd.chksum_write");
-
- gbe_rw_size = cmd->rw_size;
-
- switch (gbe_rw_size) {
- case GBE_PART_SIZE:
- case NVM_SIZE:
- break;
- default:
- err(EINVAL, "Unsupported rw_size: %lu",
- (unsigned long)gbe_rw_size);
- }
-
- if (gbe_rw_size > GBE_PART_SIZE)
- err(EINVAL, "rw_size larger than GbE part: %lu",
- (unsigned long)gbe_rw_size);
-
- _flag = (cmd->flags & O_ACCMODE);
-
- if (_flag != O_RDONLY &&
- _flag != O_RDWR)
- err(EINVAL, "invalid cmd.flags setting");
-}
-
-void
-set_cmd(int argc, char *argv[])
-{
- struct xstate *x = xstatus();
- const char *cmd;
-
- unsigned long c;
-
- for (c = 0; c < items(x->cmd); c++) {
-
- cmd = x->cmd[c].str;
-
- /* not the right command */
- if (xstrxcmp(argv[2], cmd, MAX_CMD_LEN) != 0)
- continue;
-
- /* valid command found */
- if (argc >= x->cmd[c].argc) {
- x->no_cmd = 0;
- x->i = c; /* set command */
-
- return;
- }
-
- err(EINVAL,
- "Too few args on command '%s'", cmd);
- }
-
- x->no_cmd = 1;
-}
-
-void
-set_cmd_args(int argc, char *argv[])
-{
- struct xstate *x = xstatus();
- struct commands *cmd;
- struct xfile *f;
- unsigned long i;
-
- i = x->i;
- cmd = &x->cmd[i];
- f = &x->f;
-
- if (!valid_command(i) || argc < 3)
- usage();
-
- if (x->no_cmd)
- usage();
-
- /* Maintainer bugs */
- if (cmd->arg_part && argc < 4)
- err(EINVAL,
- "arg_part set for command that needs argc4");
-
- if (cmd->arg_part && i == CMD_SETMAC)
- err(EINVAL,
- "arg_part set on CMD_SETMAC");
-
- if (i == CMD_SETMAC) {
-
- if (argc >= 4)
- x->mac.str = argv[3];
- else
- x->mac.str = x->mac.rmac;
-
- } else if (cmd->arg_part) {
-
- f->part = conv_argv_part_num(argv[3]);
- }
-}
-
-unsigned long
-conv_argv_part_num(const char *part_str)
-{
- unsigned char ch;
-
- if (part_str[0] == '\0' || part_str[1] != '\0')
- err(EINVAL, "Partnum string '%s' wrong length", part_str);
-
- /* char signedness is implementation-defined */
- ch = (unsigned char)part_str[0];
- if (ch < '0' || ch > '1')
- err(EINVAL, "Bad part number (%c)", ch);
-
- return (unsigned long)(ch - '0');
-}
-void
-run_cmd(void)
-{
- struct xstate *x = xstatus();
- unsigned long i;
- void (*run)(void);
-
- i = x->i;
- run = x->cmd[i].run;
-
- check_command_num(i);
-
- if (run == NULL)
- err(EINVAL, "Command %lu: null ptr", i);
-
- run();
-
- for (i = 0; i < items(x->cmd); i++)
- x->cmd[i].run = cmd_helper_err;
-}
-
-void
-check_command_num(unsigned long c)
-{
- if (!valid_command(c))
- err(EINVAL, "Invalid run_cmd arg: %lu",
- (unsigned long)c);
-}
-
-unsigned char
-valid_command(unsigned long c)
-{
- struct xstate *x = xstatus();
- struct commands *cmd;
-
- if (c >= items(x->cmd))
- return 0;
-
- cmd = &x->cmd[c];
-
- if (c != cmd->chk)
- err(EINVAL,
- "Invalid cmd chk value (%lu) vs arg: %lu",
- cmd->chk, c);
-
- return 1;
-}
-
-void
-cmd_helper_setmac(void)
-{
- struct xstate *x = xstatus();
- unsigned long partnum;
- struct macaddr *mac;
-
- mac = &x->mac;
-
- check_cmd(cmd_helper_setmac, "setmac");
-
- printf("MAC address to be written: %s\n", mac->str);
- parse_mac_string();
-
- for (partnum = 0; partnum < 2; partnum++)
- write_mac_part(partnum);
-}
-
-void
-parse_mac_string(void)
-{
- struct xstate *x = xstatus();
- struct macaddr *mac;
-
- unsigned long mac_byte;
-
- mac = &x->mac;
-
- if (xstrxlen(x->mac.str, 18) != 17)
- err(EINVAL, "MAC address is the wrong length");
-
- memset(mac->mac_buf, 0, sizeof(mac->mac_buf));
-
- for (mac_byte = 0; mac_byte < 6; mac_byte++)
- set_mac_byte(mac_byte);
-
- if ((mac->mac_buf[0] | mac->mac_buf[1] | mac->mac_buf[2]) == 0)
- err(EINVAL, "Must not specify all-zeroes MAC address");
-
- if (mac->mac_buf[0] & 1)
- err(EINVAL, "Must not specify multicast MAC address");
-}
-
-void
-set_mac_byte(unsigned long mac_byte_pos)
-{
- struct xstate *x = xstatus();
- struct macaddr *mac;
-
- char separator;
-
- unsigned long mac_str_pos;
- unsigned long mac_nib_pos;
-
- mac = &x->mac;
-
- mac_str_pos = mac_byte_pos * 3;
-
- if (mac_str_pos < 15) {
- if ((separator = mac->str[mac_str_pos + 2]) != ':')
- err(EINVAL, "Invalid MAC address separator '%c'",
- separator);
- }
-
- for (mac_nib_pos = 0; mac_nib_pos < 2; mac_nib_pos++)
- set_mac_nib(mac_str_pos, mac_byte_pos, mac_nib_pos);
-}
-
-void
-set_mac_nib(unsigned long mac_str_pos,
- unsigned long mac_byte_pos, unsigned long mac_nib_pos)
-{
- struct xstate *x = xstatus();
- struct macaddr *mac;
-
- char mac_ch;
- unsigned short hex_num;
-
- mac = &x->mac;
-
- mac_ch = mac->str[mac_str_pos + mac_nib_pos];
-
- if ((hex_num = hextonum(mac_ch)) > 15)
- err(EINVAL, "Invalid character '%c'",
- mac->str[mac_str_pos + mac_nib_pos]);
-
- /*
- * If random, ensure that local/unicast bits are set.
- */
- if ((mac_byte_pos == 0) && (mac_nib_pos == 1) &&
- ((mac_ch | 0x20) == 'x' ||
- (mac_ch == '?')))
- hex_num = (hex_num & 0xE) | 2; /* local, unicast */
-
- /*
- * MAC words stored big endian in-file, little-endian
- * logically, so we reverse the order.
- */
- mac->mac_buf[mac_byte_pos >> 1] |= hex_num <<
- (((mac_byte_pos & 1) << 3) /* left or right byte? */
- | ((mac_nib_pos ^ 1) << 2)); /* left or right nib? */
-}
-
-void
-write_mac_part(unsigned long partnum)
-{
- struct xstate *x = xstatus();
- struct xfile *f;
- struct macaddr *mac;
-
- unsigned long w;
-
- f = &x->f;
- mac = &x->mac;
-
- check_bin(partnum, "part number");
- if (!f->part_valid[partnum])
- return;
-
- for (w = 0; w < 3; w++)
- set_nvm_word(w, partnum, mac->mac_buf[w]);
-
- printf("Wrote MAC address to part %lu: ",
- (unsigned long)partnum);
- print_mac_from_nvm(partnum);
-}
-
-void
-cmd_helper_dump(void)
-{
- struct xstate *x = xstatus();
- struct xfile *f;
-
- unsigned long p;
-
- f = &x->f;
-
- check_cmd(cmd_helper_dump, "dump");
-
- f->part_valid[0] = good_checksum(0);
- f->part_valid[1] = good_checksum(1);
-
- for (p = 0; p < 2; p++) {
-
- if (!f->part_valid[p]) {
-
- fprintf(stderr,
- "BAD checksum %04x in part %lu (expected %04x)\n",
- nvm_word(NVM_CHECKSUM_WORD, p),
- (unsigned long)p,
- calculated_checksum(p));
- }
-
- printf("MAC (part %lu): ",
- (unsigned long)p);
-
- print_mac_from_nvm(p);
-
- hexdump(p);
- }
-}
-
-void
-print_mac_from_nvm(unsigned long partnum)
-{
- unsigned long c;
- unsigned short val16;
-
- for (c = 0; c < 3; c++) {
- val16 = nvm_word(c, partnum);
- printf("%02x:%02x",
- (unsigned int)(val16 & 0xff),
- (unsigned int)(val16 >> 8));
- if (c == 2)
- printf("\n");
- else
- printf(":");
- }
-}
-
-void
-hexdump(unsigned long partnum)
-{
- unsigned long c;
- unsigned long row;
- unsigned short val16;
-
- for (row = 0; row < 8; row++) {
-
- printf("%08lx ",
- (unsigned long)((unsigned long)row << 4));
-
- for (c = 0; c < 8; c++) {
-
- val16 = nvm_word((row << 3) + c, partnum);
-
- if (c == 4)
- printf(" ");
-
- printf(" %02x %02x",
- (unsigned int)(val16 & 0xff),
- (unsigned int)(val16 >> 8));
-
- }
-
- printf("\n");
- }
-}
-
-void
-cmd_helper_swap(void)
-{
- struct xstate *x = xstatus();
- struct xfile *f;
-
- check_cmd(cmd_helper_swap, "swap");
-
- f = &x->f;
-
- x_v_memcpy(
- f->buf + (unsigned long)GBE_WORK_SIZE,
- f->buf,
- GBE_PART_SIZE);
-
- x_v_memcpy(
- f->buf,
- f->buf + (unsigned long)GBE_PART_SIZE,
- GBE_PART_SIZE);
-
- x_v_memcpy(
- f->buf + (unsigned long)GBE_PART_SIZE,
- f->buf + (unsigned long)GBE_WORK_SIZE,
- GBE_PART_SIZE);
-
- set_part_modified(0);
- set_part_modified(1);
-}
-
-void
-cmd_helper_copy(void)
-{
- struct xstate *x = xstatus();
- struct xfile *f;
-
- check_cmd(cmd_helper_copy, "copy");
-
- f = &x->f;
-
- x_v_memcpy(
- f->buf + (unsigned long)((f->part ^ 1) * GBE_PART_SIZE),
- f->buf + (unsigned long)(f->part * GBE_PART_SIZE),
- GBE_PART_SIZE);
-
- set_part_modified(f->part ^ 1);
-}
-
-void
-cmd_helper_cat(void)
-{
- struct xstate *x = xstatus();
- check_cmd(cmd_helper_cat, "cat");
-
- x->cat = 0;
- cat(0);
-}
-
-void
-cmd_helper_cat16(void)
-{
- struct xstate *x = xstatus();
- check_cmd(cmd_helper_cat16, "cat16");
-
- x->cat = 1;
- cat(1);
-}
-
-void
-cmd_helper_cat128(void)
-{
- struct xstate *x = xstatus();
- check_cmd(cmd_helper_cat128, "cat128");
-
- x->cat = 15;
- cat(15);
-}
-
-void
-cat(unsigned long nff)
-{
- struct xstate *x = xstatus();
- struct xfile *f;
-
- unsigned long p;
- unsigned long ff;
-
- f = &x->f;
-
- p = 0;
- ff = 0;
-
- if ((unsigned long)x->cat != nff) {
-
- err(ECANCELED, "erroneous call to cat");
- }
-
- fflush(NULL);
-
- memset(f->pad, 0xff, GBE_PART_SIZE);
-
- for (p = 0; p < 2; p++) {
-
- cat_buf(f->bufcmp +
- (unsigned long)(p * (f->gbe_file_size >> 1)));
-
- for (ff = 0; ff < nff; ff++) {
-
- cat_buf(f->pad);
- }
- }
-}
-
-void
-cat_buf(unsigned char *b)
-{
- if (b == NULL)
- err(errno, "null pointer in cat command");
-
- if (rw_file_exact(STDOUT_FILENO, b,
- GBE_PART_SIZE, 0, IO_WRITE, LOOP_EAGAIN, LOOP_EINTR,
- MAX_ZERO_RW_RETRY, OFF_ERR) < 0)
- err(errno, "stdout: cat");
-}
-void
-check_cmd(void (*fn)(void),
- const char *name)
-{
- struct xstate *x = xstatus();
- unsigned long i;
-
- if (x->cmd[x->i].run != fn)
- err(ECANCELED, "Running %s, but cmd %s is set",
- name, x->cmd[x->i].str);
-
- /*
- * In addition to making sure we ran
- * the right command, we now disable
- * all commands from running again
- *
- * the _nop function will just call
- * err() immediately
- */
-
- for (i = 0; i < items(x->cmd); i++)
- x->cmd[i].run = cmd_helper_err;
-}
-
-void
-cmd_helper_err(void)
-{
- err(ECANCELED,
- "Erroneously running command twice");
-}