diff options
Diffstat (limited to 'util/nvmutil')
| -rw-r--r-- | util/nvmutil/nvmutil.c | 55 | 
1 files changed, 39 insertions, 16 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index cdfcbc32..b77b28ad 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -21,6 +21,11 @@   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   */ +/* + * This file is part of the Libreboot project. Documentation available here: + * https://libreboot.org/docs/install/nvmutil.html + */ +  #include <stdint.h>  #include <string.h>  #include <stdlib.h> @@ -78,33 +83,33 @@ main(int argc, char *argv[])  	const char *strMac = NULL, *strRMac = "??:??:??:??:??:??";  #ifdef HAVE_PLEDGE -	if (pledge("stdio wpath", NULL) == -1) -		err(errno, "pledge"); +	if (pledge("stdio wpath", NULL) == -1) /* only used on openbsd */ +		err(errno, "pledge"); /* https://man.openbsd.org/pledge.2 */  #endif  	buf = (uint8_t *) &buf16;  	gbe[1] = (gbe[0] = (size_t) buf) + SIZE_4KB;  	test = 1; -	big_endian = ((uint8_t *) &test)[0] ^ 1; +	big_endian = ((uint8_t *) &test)[0] ^ 1; /* check host endianness */  	if (argc == 3) {  		if (strcmp(COMMAND, "dump") == 0) {  #ifdef HAVE_PLEDGE  			if (pledge("stdio rpath", NULL) == -1) -				err(errno, "pledge"); +				err(errno, "pledge"); /* not very puffy */  #endif  			flags = O_RDONLY;  			cmd = &cmd_dump;  		} else if (strcmp(COMMAND, "setmac") == 0) -			strMac = (char *) strRMac; +			strMac = (char *) strRMac; /* random mac address */  		else if (strcmp(COMMAND, "swap") == 0)  			cmd = &cmd_swap;  	} else if (argc == 4) {  		if (strcmp(COMMAND, "setmac") == 0) -			strMac = MAC_ADDRESS; +			strMac = MAC_ADDRESS; /* user-supplied mac address */  		else if ((!((part = PARTNUM[0] - '0') == 0 || part == 1)) -				|| PARTNUM[1]) +				|| PARTNUM[1]) /* only allow '1' or '0' */  			errno = EINVAL;  		else if (strcmp(COMMAND, "setchecksum") == 0)  			cmd = &cmd_setchecksum; @@ -129,6 +134,7 @@ main(int argc, char *argv[])  	readGbeFile(&fd, FILENAME, flags, nr); +	/* perform operation specified by the user */  	if (strMac != NULL)  		cmd_setmac(strMac);  	else if (cmd != NULL) @@ -145,6 +151,7 @@ nvmutil_exit:  	return errno;  } +/* load the gbe file into memory */  void  readGbeFile(int *fd, const char *path, int flags, size_t nr)  { @@ -174,6 +181,7 @@ readGbeFile(int *fd, const char *path, int flags, size_t nr)  	}  } +/* set mac address on valid nvm parts, per user input */  void  cmd_setmac(const char *strMac)  { @@ -193,12 +201,13 @@ cmd_setmac(const char *strMac)  		if (!validChecksum(partnum))  			continue;  		for (int w = 0; w < 3; w++) -			setWord(w, partnum, mac[w]); +			setWord(w, partnum, mac[w]); /* do not use memcpy! */  		part = partnum;  		cmd_setchecksum();  	}  } +/* read mac address from user input */  int  parseMacAddress(const char *strMac, uint16_t *mac)  { @@ -239,11 +248,12 @@ hextonum(char ch)  	else if ((ch >= 'a') && (ch <= 'f'))  		return ch - 'a' + 10;  	else if (ch == '?') -		return rhex(); +		return rhex(); /* random number */  	else  		return 16;  } +/* generate a random number from 0 to 15, the unix way */  uint8_t  rhex(void)  { @@ -261,6 +271,7 @@ rhex(void)  	return rval;  } +/* show mac address and hexdump of each nvm part */  void  cmd_dump(void)  { @@ -276,6 +287,7 @@ cmd_dump(void)  		errno = 0;  } +/* show formatted mac address contained within the nvm part */  void  showmac(int partnum)  { @@ -290,6 +302,7 @@ showmac(int partnum)  	}  } +/* output a hexdump of both nvm parts, bytes reversed to big-endian order */  void  hexdump(int partnum)  { @@ -304,6 +317,7 @@ hexdump(int partnum)  	}  } +/* set a valid checksum on a given part */  void  cmd_setchecksum(void)  { @@ -313,6 +327,7 @@ cmd_setchecksum(void)  	setWord(0x3F, part, 0xBABA - val16);  } +/* set invalid checksum, intentionally */  void  cmd_brick(void)  { @@ -320,26 +335,28 @@ cmd_brick(void)  		setWord(0x3F, part, (word(0x3F, part)) ^ 0xFF);  } +/* swap the words of each part with each other */  void  cmd_swap(void)  {  	if (validChecksum(1) || validChecksum(0)) { -		gbe[0] ^= gbe[1]; +		gbe[0] ^= gbe[1]; /* speed hack: xorswap pointers, not words */  		gbe[1] ^= gbe[0];  		gbe[0] ^= gbe[1]; -		gbeFileModified = 1; +		gbeFileModified = 1; /* not using setWord, so must set these */  		nvmPartModified[0] = 1;  		nvmPartModified[1] = 1;  		errno = 0;  	}  } +/* overwrite one part with the other */  void  cmd_copy(void)  {  	if (validChecksum(part)) { -		gbe[part ^ 1] = gbe[part]; -		gbeFileModified = 1; +		gbe[part ^ 1] = gbe[part]; /* pointer-based speed hack */ +		gbeFileModified = 1; /* not using setWord, so must set these */  		nvmPartModified[part ^ 1] = 1;  	}  } @@ -358,12 +375,14 @@ validChecksum(int partnum)  	return 0;  } +/* fetch a word from gbe buffer */  uint16_t  word(int pos16, int partnum)  {  	return buf16[pos16 + (partnum << 11)];  } +/* write a word to gbe buffer, and record that a write has occured */  void  setWord(int pos16, int partnum, uint16_t val16)  { @@ -375,6 +394,7 @@ setWord(int pos16, int partnum, uint16_t val16)  	nvmPartModified[partnum] = 1;  } +/* big-endian host compatibility: called post-read and again pre-write */  void  byteswap(int n, int partnum)  { @@ -382,24 +402,27 @@ byteswap(int n, int partnum)  	uint8_t *nbuf = (uint8_t *) gbe[partnum];  	for (int w = 0; w < wcount; w++) {  		b1 = b2 = w << 1; + +		/* xor-based swap method */  		nbuf[b1] ^= nbuf[++b2];  		nbuf[b2] ^= nbuf[b1];  		nbuf[b1] ^= nbuf[b2];  	}  } +/* called after all operations are done, if gbe was modified */  void  writeGbeFile(int *fd, const char *filename)  {  	int p, nw;  	errno = 0;  	if ((gbe[0] != gbe[1]) && (gbe[0] < gbe[1])) -		nw = 128; /* copy/swap command, so only write the nvm part */ +		nw = 128; /* write only the nvm part */  	else -		nw = SIZE_4KB; +		nw = SIZE_4KB; /* copy/swap, so only write everything */  	for (p = 0; p < 2; p++) { -		if (gbe[0] > gbe[1]) +		if (gbe[0] > gbe[1]) /* write sequentially on-disk */  			p ^= 1;  		if (!nvmPartModified[p])  			goto next_part;  | 
