diff options
Diffstat (limited to 'util/nvmutil/nvmutil.c')
| -rw-r--r-- | util/nvmutil/nvmutil.c | 514 |
1 files changed, 329 insertions, 185 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 87a20bd0..07f3dc03 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -4,32 +4,51 @@ #include <sys/stat.h> -#include <dirent.h> -#include <err.h> #include <errno.h> #include <fcntl.h> +#include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -void cmd_setchecksum(void), cmd_brick(void), swap(int partnum), writeGbe(void), - cmd_dump(void), cmd_setmac(void), readGbe(void), print_mac_address(int), - hexdump(int), set_mac_nib(int, int, uint8_t *), checkdir(const char *), - parseMacString(const char *strMac, uint16_t *mac), cmd_swap(void), - openFiles(void), cmd_copy(void), writeGbe_part(int), readGbe_part(int), - set_cmd(int, char **), setWord(int, int, uint16_t), check_bounds(int, int), - xopen(int *, const char *, int p, struct stat *), checkMacSeparator(int), - set_mac_byte(int, uint64_t *), usage(char*), set_io_flags(int, char **), - err_if(int); -int goodChecksum(int partnum), write_mac_part(int), set_err(int); -uint8_t hextonum(char chs), rhex(void); -uint16_t word(int, int); - -#define COMMAND argv[2] -#define MAC_ADDRESS argv[3] -#define PARTN argv[3] +static void set_cmd(int, char **); +static void check_cmd_args(int, char **); +static void set_io_flags(int, char **); +static void open_files(void); +static void checkdir(const char *); +static void xopen(int *, const char *, int, struct stat *); +static void read_gbe(void); +static void read_gbe_part(int, int); +static void cmd_setmac(void); +static void parse_mac_string(void); +static void set_mac_byte(int, uint64_t *); +static void check_mac_separator(int); +static void set_mac_nib(int, int, uint8_t *); +static uint8_t hextonum(char); +static uint8_t rhex(void); +static int write_mac_part(int); +static void cmd_dump(void); +static void print_mac_address(int); +static void hexdump(int); +static void cmd_setchecksum(void); +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 void write_gbe(void); +static void write_gbe_part(int); +static void swap(int); +static void usage(void); +static void err_if(int); +static void err(int, const char *, ...); +static const char *getnvmprogname(void); +static int set_err(int); + #define NVM_CHECKSUM 0xBABA #define NVM_CHECKSUM_WORD 0x3F #define NVM_SIZE 128 @@ -39,38 +58,53 @@ uint16_t word(int, int); #define SIZE_16KB 0x4000 #define SIZE_128KB 0x20000 -uint8_t buf[SIZE_8KB]; -uint16_t mac[3] = {0, 0, 0}; -size_t partsize; -int flags, rfd, fd, part, e = 1; +#define items(x) (sizeof((x)) / sizeof((x)[0])) + +static uint8_t buf[SIZE_8KB]; +static uint16_t macbuf[3]; +static size_t partsize; + +static int flags; +static int rfd; +static int fd; +static int part; +static int invert; +static int part_modified[2]; -const char *strMac = NULL, *strRMac = "xx:xx:xx:xx:xx:xx", *fname = ""; +static const char *mac = NULL; +static const char *rmac = "xx:xx:xx:xx:xx:xx"; +static const char *fname = ""; +static const char *argv0; -typedef struct op { - char *str; +struct op { + const char *str; void (*cmd)(void); int args; -} op_t; -op_t op[] = { -{ .str = "dump", .cmd = cmd_dump, .args = 3 }, -{ .str = "setmac", .cmd = cmd_setmac, .args = 3 }, -{ .str = "swap", .cmd = cmd_swap, .args = 3 }, -{ .str = "copy", .cmd = cmd_copy, .args = 4 }, -{ .str = "brick", .cmd = cmd_brick, .args = 4 }, -{ .str = "setchecksum", .cmd = cmd_setchecksum, .args = 4 }, }; -void (*cmd)(void) = NULL; +static const struct op ops[] = { + { "dump", cmd_dump, 3 }, + { "setmac", cmd_setmac, 3 }, + { "swap", cmd_swap, 3 }, + { "copy", cmd_copy, 4 }, + { "brick", cmd_brick, 4 }, + { "setchecksum", cmd_setchecksum, 4 }, +}; + +static void (*cmd)(void) = NULL; int main(int argc, char *argv[]) { + argv0 = argv[0]; + if (argc < 2) + usage(); + fname = argv[1]; #ifdef __OpenBSD__ err_if(pledge("stdio rpath wpath unveil", NULL) == -1); err_if(unveil("/dev/urandom", "r") == -1); #endif set_cmd(argc, argv); - - fname = argv[1]; + check_cmd_args(argc, argv); set_io_flags(argc, argv); #ifdef __OpenBSD__ if (flags == O_RDONLY) { @@ -83,63 +117,82 @@ main(int argc, char *argv[]) err_if(pledge("stdio rpath wpath", NULL) == -1); } #endif - openFiles(); + open_files(); #ifdef __OpenBSD__ err_if(pledge("stdio", NULL) == -1); #endif - readGbe(); + read_gbe(); (*cmd)(); - writeGbe(); + write_gbe(); + + err_if(close(fd) == -1); + err_if(close(rfd) == -1); err_if((errno != 0) && (cmd != cmd_dump)); return errno ? EXIT_FAILURE : EXIT_SUCCESS; } -void +static void set_cmd(int argc, char *argv[]) { - if (argc < 2) { - usage(argv[0]); - } else if (argc > 2) { - for (int i = 0; (i < 6) && (cmd == NULL); i++) { - if (strcmp(COMMAND, op[i].str) != 0) - continue; - if (argc >= op[i].args) { - cmd = op[i].cmd; - break; - } - err(set_err(EINVAL), "Too few args on command '%s'", - op[i].str); - } - } else { /* argc == 2 */ + size_t i; + const char *arg_cmd; + + if (argc == 2) { cmd = cmd_setmac; + return; } + arg_cmd = argv[2]; + + for (i = 0; (i < items(ops)) && (cmd == NULL); i++) { + if (strcmp(arg_cmd, ops[i].str) != 0) + continue; + if (argc >= ops[i].args) { + cmd = ops[i].cmd; + break; + } + err(set_err(EINVAL), "Too few args on command '%s'", + ops[i].str); + } +} + +static void +check_cmd_args(int argc, char *argv[]) +{ + const char *arg_cmd = argv[2]; + if ((cmd == NULL) && (argc > 2)) { /* nvm gbe [MAC] */ - strMac = COMMAND; + mac = arg_cmd; cmd = cmd_setmac; } else if (cmd == cmd_setmac) { /* nvm gbe setmac [MAC] */ - strMac = strRMac; /* random MAC */ + mac = rmac; /* random MAC */ if (argc > 3) - strMac = MAC_ADDRESS; + mac = argv[3]; } else if ((cmd != NULL) && (argc > 3)) { /* user-supplied partnum */ - err_if((errno = (!((part = PARTN[0] - '0') == 0 || part == 1)) - || PARTN[1] ? EINVAL : errno)); /* only allow '0' or '1' */ + part = argv[3][0] - '0'; + if (!((part == 0 || part == 1) && argv[3][1] == '\0')) + err(set_err(EINVAL), "Bad partnum: %s", argv[3]); } - err_if((errno = (cmd == NULL) ? EINVAL : errno)); + + if (cmd == NULL) + err(set_err(EINVAL), "Bad command"); } -void +static void set_io_flags(int argc, char *argv[]) { + const char *arg_cmd = argv[2]; + flags = O_RDWR; - if (argc > 2) - if (strcmp(COMMAND, "dump") == 0) + if (argc > 2) { + if (strcmp(arg_cmd, "dump") == 0) flags = O_RDONLY; + } } -void -openFiles(void) +static void +open_files(void) { struct stat st; struct stat st_rfd; @@ -162,19 +215,17 @@ openFiles(void) } } -void +static void checkdir(const char *path) { struct stat st; - err_if (stat(path, &st) == -1); + if (stat(path, &st) == -1) + err(set_err(ECANCELED), "%s", path); if (S_ISDIR(st.st_mode)) err(set_err(EISDIR), "%s", path); - if (errno == ENOTDIR) - errno = 0; - err_if(errno); } -void +static void xopen(int *f, const char *l, int p, struct stat *st) { if ((*f = open(l, p)) == -1) @@ -183,94 +234,118 @@ xopen(int *f, const char *l, int p, struct stat *st) err(set_err(ECANCELED), "%s", l); } -void -readGbe(void) +static void +read_gbe(void) { - for (int p = 0; p < 2; p++) - readGbe_part(p); + int p; + int do_read[2] = {1, 1}; + + 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)) + invert = 1; + + for (p = 0; p < 2; p++) { + if (do_read[p]) + read_gbe_part(p, invert); + } } -void -readGbe_part(int p) +static void +read_gbe_part(int p, int invert) { - if (pread(fd, buf + (SIZE_4KB * p), SIZE_4KB, p * partsize) != SIZE_4KB) + if (pread(fd, buf + (SIZE_4KB * (p ^ invert)), SIZE_4KB, p * partsize) + != SIZE_4KB) err(set_err(ECANCELED), "Can't read %d b from '%s' p%d", SIZE_4KB, fname, p); - swap(p); /* handle big-endian host CPU */ + swap(p ^ invert); /* handle big-endian host CPU */ } -void +static void cmd_setmac(void) { + int partnum; int mac_updated = 0; - parseMacString(strMac, mac); + parse_mac_string(); - printf("MAC address to be written: %s\n", strMac); + printf("MAC address to be written: %s\n", mac); - for (int partnum = 0; partnum < 2; partnum++) + for (partnum = 0; partnum < 2; partnum++) mac_updated |= write_mac_part(partnum); if (mac_updated) errno = 0; } -void -parseMacString(const char *strMac, uint16_t *mac) +static void +parse_mac_string(void) { + int mac_pos; uint64_t total = 0; - if (strnlen(strMac, 20) != 17) + + if (strnlen(mac, 20) != 17) err(set_err(EINVAL), "Invalid MAC address string length"); - for (int strMacPos = 0; strMacPos < 16; strMacPos += 3) - set_mac_byte(strMacPos, &total); + for (mac_pos = 0; mac_pos < 16; mac_pos += 3) + set_mac_byte(mac_pos, &total); if (total == 0) err(set_err(EINVAL), "Invalid MAC (all-zero MAC address)"); - if (mac[0] & 1) + if (macbuf[0] & 1) err(set_err(EINVAL), "Invalid MAC (multicast bit set)"); } -void -set_mac_byte(int strMacPos, uint64_t *total) +static void +set_mac_byte(int mac_pos, uint64_t *total) { + int nib; uint8_t h = 0; - checkMacSeparator(strMacPos); + check_mac_separator(mac_pos); - for (int nib = 0; nib < 2; nib++, *total += h) - set_mac_nib(strMacPos, nib, &h); + for (nib = 0; nib < 2; nib++, *total += h) + set_mac_nib(mac_pos, nib, &h); } -void -checkMacSeparator(int strMacPos) +static void +check_mac_separator(int mac_pos) { - if (strMacPos == 15) + char separator; + + if (mac_pos == 15) return; - char separator = strMac[strMacPos + 2]; - if (separator == ':') + if ((separator = mac[mac_pos + 2]) == ':') return; + err(set_err(EINVAL), "Invalid MAC address separator '%c'", separator); } -void -set_mac_nib(int strMacPos, int nib, uint8_t *h) +static void +set_mac_nib(int mac_pos, int nib, uint8_t *h) { - int byte = strMacPos / 3; + int byte = mac_pos / 3; - if ((*h = hextonum(strMac[strMacPos + nib])) > 15) + if ((*h = hextonum(mac[mac_pos + nib])) > 15) err(set_err(EINVAL), "Invalid character '%c'", - strMac[strMacPos + nib]); + mac[mac_pos + nib]); /* If random, ensure that local/unicast bits are set */ - if ((byte == 0) && (nib == 1)) - if ((strMac[strMacPos + nib] == '?') || - (strMac[strMacPos + nib] == 'x') || - (strMac[strMacPos + nib] == 'X')) /* random */ + 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 */ + } - mac[byte >> 1] |= ((uint16_t ) *h) << ((8 * (byte % 2)) + + macbuf[byte >> 1] |= ((uint16_t ) *h) << ((8 * (byte % 2)) + (4 * (nib ^ 1))); } -uint8_t +static uint8_t hextonum(char ch) { if ((ch >= '0') && (ch <= '9')) @@ -281,26 +356,35 @@ hextonum(char ch) return ch - 'a' + 10; else if ((ch == '?') || (ch == 'x') || (ch == 'X')) return rhex(); /* random hex value */ - return 16; /* error: invalid character */ + else + return 16; /* error: invalid character */ } -uint8_t +static uint8_t rhex(void) { - static uint8_t n = 0, rnum[16]; - if (!n) - err_if(pread(rfd, (uint8_t *) &rnum, (n = 15) + 1, 0) == -1); + static uint8_t n = 0; + static uint8_t rnum[12]; + + if (!n) { + n = sizeof(rnum) - 1; + err_if(read(rfd, (uint8_t *) &rnum, n + 1) == -1); + } + return rnum[n--] & 0xf; } -int +static int write_mac_part(int partnum) { - if (!goodChecksum(part = partnum)) + int w; + + part = partnum; + if (!good_checksum(partnum)) return 0; - for (int w = 0; w < 3; w++) - setWord(w, partnum, mac[w]); + for (w = 0; w < 3; w++) + set_word(w, partnum, macbuf[w]); printf("Wrote MAC address to part %d: ", partnum); print_mac_address(partnum); @@ -309,26 +393,30 @@ write_mac_part(int partnum) return 1; } -void +static void cmd_dump(void) { - for (int partnum = 0, numInvalid = 0; partnum < 2; partnum++) { - if (!goodChecksum(partnum)) - ++numInvalid; + int partnum; + int num_invalid = 0; + + for (partnum = 0; partnum < 2; partnum++) { + if (!good_checksum(partnum)) + ++num_invalid; printf("MAC (part %d): ", partnum); print_mac_address(partnum); hexdump(partnum); - - if ((numInvalid < 2) && (partnum)) - errno = 0; } + + if ((num_invalid < 2)) + errno = 0; } -void +static void print_mac_address(int partnum) { - for (int c = 0; c < 3; c++) { + int c; + for (c = 0; c < 3; c++) { uint16_t val16 = word(c, partnum); printf("%02x:%02x", val16 & 0xff, val16 >> 8); if (c == 2) @@ -338,12 +426,15 @@ print_mac_address(int partnum) } } -void +static void hexdump(int partnum) { - for (int row = 0; row < 8; row++) { + int c; + int row; + + for (row = 0; row < 8; row++) { printf("%08x ", row << 4); - for (int c = 0; c < 8; c++) { + for (c = 0; c < 8; c++) { uint16_t val16 = word((row << 3) + c, partnum); if (c == 4) printf(" "); @@ -353,141 +444,194 @@ hexdump(int partnum) } } -void +static void cmd_setchecksum(void) { + int c; uint16_t val16 = 0; - for (int c = 0; c < NVM_CHECKSUM_WORD; c++) + + for (c = 0; c < NVM_CHECKSUM_WORD; c++) val16 += word(c, part); - setWord(NVM_CHECKSUM_WORD, part, NVM_CHECKSUM - val16); + set_word(NVM_CHECKSUM_WORD, part, NVM_CHECKSUM - val16); } -void +static void cmd_brick(void) { - if (goodChecksum(part)) - setWord(NVM_CHECKSUM_WORD, part, + if (good_checksum(part)) + set_word(NVM_CHECKSUM_WORD, part, ((word(NVM_CHECKSUM_WORD, part)) ^ 0xFF)); } -void +static void cmd_copy(void) { - err_if(!goodChecksum(part)); - for (int c = 0; c < (SIZE_4KB >> 1); c++) - setWord(c, part ^ 1, word(c, part)); + err_if(!good_checksum(part ^ 1)); + part_modified[part ^ 1] = 1; } -void -cmd_swap(void) { - err_if(!(goodChecksum(0) || goodChecksum(1))); +static void +cmd_swap(void) +{ + err_if(!(good_checksum(0) || good_checksum(1))); errno = 0; - for (int c = 0; c < (SIZE_4KB >> 1); c++) { - uint16_t chg = word(c, 0); - setWord(c, 0, word(c, 1)); - setWord(c, 1, chg); - } + part_modified[1] = part_modified[0] = 1; } -int -goodChecksum(int partnum) +static int +good_checksum(int partnum) { + int w; uint16_t total = 0; - for(int w = 0; w <= NVM_CHECKSUM_WORD; w++) + for (w = 0; w <= NVM_CHECKSUM_WORD; w++) total += word(w, partnum); if (total == NVM_CHECKSUM) return 1; - fprintf(stderr, "WARNING: BAD checksum in part %d\n", partnum); + fprintf(stderr, "WARNING: BAD checksum in part %d\n", + partnum ^ invert); (void) set_err(ECANCELED); return 0; } -uint16_t +static uint16_t word(int pos16, int p) { - check_bounds(pos16, p); + check_bound(pos16, p); return ((uint16_t *) (buf + (SIZE_4KB * p)))[pos16]; } -void -setWord(int pos16, int p, uint16_t val16) +static void +set_word(int pos16, int p, uint16_t val16) { - check_bounds(pos16, p); + check_bound(pos16, p); + part_modified[p] = 1; ((uint16_t *) (buf + (SIZE_4KB * p)))[pos16] = val16; } -void -check_bounds(int c, int p) +static void +check_bound(int c, int p) { if ((p != 0) && (p != 1)) - err(set_err(EINVAL), "check_bounds: invalid partnum %d", p); + err(set_err(EINVAL), "check_bound: invalid partnum %d", p); if ((c < 0) || (c >= (SIZE_4KB >> 1))) - err(set_err(EINVAL), "check_bounds: out of bounds %d", c); + err(set_err(EINVAL), "check_bound: out of bounds %d", c); } -void -writeGbe(void) +static void +write_gbe(void) { - if (flags != O_RDONLY) - for (int p = 0; p < 2; p++) - writeGbe_part(p); - err_if(close(fd) == -1); + int p; + + if (flags == O_RDONLY) + return; + + for (p = 0; p < 2; p++) { + if (part_modified[p]) + write_gbe_part(p); + } } -void -writeGbe_part(int p) +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, p * partsize) != SIZE_4KB) + + if (pwrite(fd, buf + (SIZE_4KB * p), + SIZE_4KB, p * partsize) != SIZE_4KB) { err(set_err(ECANCELED), "Can't write %d b to '%s' p%d", SIZE_4KB, fname, p); + } } -void +static void swap(int partnum) { + size_t w; + size_t x; + + int e = 1; uint8_t *n = buf + (SIZE_4KB * partnum); - for (size_t w = NVM_SIZE * ((uint8_t *) &e)[0], x = 1; - w < NVM_SIZE; w += 2, x += 2) { + if (((uint8_t *) &e)[0] == 1) + return; /* Little-endian host CPU; no swap needed. */ + + /* + * The host CPU stores bytes in big-endian order. + * GbE files store bytes in little-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; } } -void -usage(char *util) +static void +usage(void) { + const char *util = getnvmprogname(); #ifdef __OpenBSD__ err_if(pledge("stdio", NULL) == -1); #endif fprintf(stderr, "Modify Intel GbE NVM images e.g. set MAC\n" "USAGE:\n" - "%s FILE dump\n" - " %s FILE\n # same as setmac without arg\n" - " %s FILE setmac [MAC]\n" - " %s FILE swap\n" - " %s FILE copy 0|1\n" - " %s FILE brick 0|1\n" - " %s FILE setchecksum 0|1\n", + "\t%s FILE dump\n" + "\t%s FILE # same as setmac without [MAC]\n" + "\t%s FILE setmac [MAC]\n" + "\t%s FILE swap\n" + "\t%s FILE copy 0|1\n" + "\t%s FILE brick 0|1\n" + "\t%s FILE setchecksum 0|1\n", util, util, util, util, util, util, util); err(set_err(ECANCELED), "Too few arguments"); } -void +static void err_if(int x) { if (x) err(set_err(ECANCELED), "%s", fname); } -int +static void +err(int rval, const char *msg, ...) +{ + va_list args; + + fprintf(stderr, "%s: ", getnvmprogname()); + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + (void) set_err(ECANCELED); + fprintf(stderr, ": %s", strerror(errno)); + + fprintf(stderr, "\n"); + exit(rval); +} + +static const char * +getnvmprogname(void) +{ + const char *p; + + if ((argv0 == NULL) || (*argv0 == '\0')) + return ""; + + if ((p = strrchr(argv0, '/'))) + return p + 1; + else + return argv0; +} + +static int set_err(int x) { errno = errno ? errno : x; |
