diff options
| author | Leah Rowe <leah@libreboot.org> | 2022-11-17 12:07:09 +0000 | 
|---|---|---|
| committer | Leah Rowe <leah@libreboot.org> | 2022-11-17 12:07:09 +0000 | 
| commit | b3b3642fe229a8546e869ff4c058606ddfb02f0e (patch) | |
| tree | ab33d21338ca7e61de3a79e4e3657f1e716e0e04 /util | |
| parent | 8740404e4e3b003cc36a6e4f46628185b4613e6b (diff) | |
assimilate nvmutil
Diffstat (limited to 'util')
| -rw-r--r-- | util/nvmutil/AUTHORS | 1 | ||||
| -rw-r--r-- | util/nvmutil/COPYING | 20 | ||||
| -rw-r--r-- | util/nvmutil/ChangeLog.md | 8 | ||||
| -rw-r--r-- | util/nvmutil/Makefile | 33 | ||||
| -rw-r--r-- | util/nvmutil/README.md | 4 | ||||
| -rw-r--r-- | util/nvmutil/nvmutil.c | 319 | 
6 files changed, 385 insertions, 0 deletions
| diff --git a/util/nvmutil/AUTHORS b/util/nvmutil/AUTHORS new file mode 100644 index 00000000..f3c00385 --- /dev/null +++ b/util/nvmutil/AUTHORS @@ -0,0 +1 @@ +Leah Rowe diff --git a/util/nvmutil/COPYING b/util/nvmutil/COPYING new file mode 100644 index 00000000..17374089 --- /dev/null +++ b/util/nvmutil/COPYING @@ -0,0 +1,20 @@ +Copyright (C) 2022 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. diff --git a/util/nvmutil/ChangeLog.md b/util/nvmutil/ChangeLog.md new file mode 100644 index 00000000..e1ed5754 --- /dev/null +++ b/util/nvmutil/ChangeLog.md @@ -0,0 +1,8 @@ +This change log has moved. Please refer here for historical pre-osboot-merge +changes: + +<https://libreboot.org/docs/install/nvmutilimport.html> + +Osboot merged with Libreboot on November 17th, 2022. For nvmutil changes after +this date, please check regular Libreboot release announcements which shall +now specify any such changes. diff --git a/util/nvmutil/Makefile b/util/nvmutil/Makefile new file mode 100644 index 00000000..a69c0f0e --- /dev/null +++ b/util/nvmutil/Makefile @@ -0,0 +1,33 @@ +# +# Makefile for nvmutils +# +# Copyright (C) 2022 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. +# + +CC=cc +CFLAGS=-Os -Wall -Wextra -Werror -pedantic + +all: +	$(CC) $(CFLAGS) nvmutil.c -o nvm + +clean: +	rm -f nvm diff --git a/util/nvmutil/README.md b/util/nvmutil/README.md new file mode 100644 index 00000000..03a25bc4 --- /dev/null +++ b/util/nvmutil/README.md @@ -0,0 +1,4 @@ + +This documentation has become part of lbwww. See: + +<https://libreboot.org/docs/install/nvmutil.html> diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c new file mode 100644 index 00000000..9f93ae59 --- /dev/null +++ b/util/nvmutil/nvmutil.c @@ -0,0 +1,319 @@ +/*  + * Copyright (C) 2022 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. + */ + +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <dirent.h> +#ifdef HAVE_PLEDGE +#include <err.h> +#endif + +ssize_t readFromFile(int *fd, uint8_t *buf, const char *path, int flags, +	size_t size); +void setmac(const char *strMac); +void cmd(const char *command); +int validChecksum(int partnum); +uint16_t word(int pos16, int partnum); +void setWord(int pos16, int partnum, uint16_t val); +void byteswap(uint8_t *byte); + +#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 + +uint8_t gbe[SIZE_8KB]; +int part, modified = 0; + +uint16_t test; +uint8_t little_endian; + +int +main(int argc, char *argv[]) +{ +	int fd; +	int flags = O_RDWR; +	char *strMac = NULL; +	char *strRMac = "??:??:??:??:??:??"; + +	test = 1; +	little_endian = ((uint8_t *) &test)[0]; + +#ifdef HAVE_PLEDGE +	if (pledge("stdio wpath", NULL) == -1) +		err(1, "pledge"); +#endif +	if (argc == 3) { +		if (strcmp(COMMAND, "dump") == 0) { +#ifdef HAVE_PLEDGE +			if (pledge("stdio rpath", NULL) == -1) +				err(1, "pledge"); +#endif +			flags = O_RDONLY; +		} else if (strcmp(COMMAND, "setmac") == 0) { +			strMac = strRMac; +		} +	} else if (argc == 4) { +		if (strcmp(COMMAND, "setmac") == 0) +			strMac = MAC_ADDRESS; +		else if ((!((part = PARTNUM[0] - '0') == 0 || part == 1)) +				|| PARTNUM[1]) +			errno = EINVAL; +	} else +		errno = EINVAL; + +	if (errno != 0) +		goto nvmutil_exit; + +	if (readFromFile(&fd, gbe, FILENAME, flags, SIZE_8KB) +		== SIZE_8KB) +	{ +		if (strMac != NULL) +			setmac(strMac); +		else +			cmd(COMMAND); + +		if (modified) { +			errno = 0; +			if (pwrite(fd, gbe, SIZE_8KB, 0) == SIZE_8KB) +				close(fd); +		} +	} + +nvmutil_exit: +	if (errno == ENOTDIR) +		errno = 0; +	if (!((errno == ECANCELED) && (flags == O_RDONLY))) +		if (errno != 0) +			fprintf(stderr, "%s\n", strerror(errno)); +	return errno; +} + +ssize_t +readFromFile(int *fd, uint8_t *buf, const char *path, int flags, size_t size) +{ +	struct stat st; + +	if (opendir(path) != NULL) { +		errno = EISDIR; +		return -1; +	} else if (((*fd) = open(path, flags)) == -1) { +		return -1; +	} else if (size == SIZE_8KB) { +		fstat((*fd), &st); +		if (st.st_size != SIZE_8KB) { +			fprintf(stderr, "Bad file size\n"); +			errno = ECANCELED; +			return -1; +		} +	} +	return read((*fd), buf, size); +} + +void +setmac(const char *strMac) +{ +	uint8_t rmac[12]; +	uint8_t o, ch, val8; +	uint16_t val16; +	int macfd, partnum, random, byte, nib; +	uint16_t mac[3] = {0, 0, 0}; +	uint64_t total = 0; + +	if (readFromFile(&macfd, rmac, "/dev/urandom", O_RDONLY, 12) != 12) +		return; +	else if (strnlen(strMac, 20) != 17) +		goto invalid_mac_address; +	for (o = 0, random = 0; o < 16; o += 3) { +		if (o != 15) +			if (strMac[o + 2] != ':') +				goto invalid_mac_address; +		byte = o / 3; +		for (nib = 0; nib < 2; nib++, total += val8) { +			ch = strMac[o + nib]; +			if ((ch >= '0') && ch <= '9') { +				val8 = ch - '0'; +			} else if ((ch >= 'A') && (ch <= 'F')) { +				val8 = ch - 'A' + 10; +			} else if ((ch >= 'a') && (ch <= 'f')) { +				val8 = ch - 'a' + 10; +			} else if (ch == '?') { +				val8 = rmac[random++] & 0xf; +				if ((byte == 0 && (nib == 1))) { +					val8 &= 0xE; +					val8 |= 2; +				} +			} else { +				goto invalid_mac_address; +			} +			val16 = val8; +			if ((byte % 2) ^ 1) +				byteswap((uint8_t *) &val16); +			val16 <<= 4 * (nib ^ 1); +			mac[byte >> 1] |= val16; +		} +	} + +	test = mac[0]; +	if (little_endian) +		byteswap((uint8_t *) &test); +	if (total == 0 || (((uint8_t *) &test)[0] & 1)) +		goto invalid_mac_address; + +	if (little_endian) +		for (o = 0; o < 3; o++) +			byteswap((uint8_t *) &mac[o]); + +	for (partnum = 0; partnum < 2; partnum++) { +		if (validChecksum(partnum)) { +			for (o = 0; o < 3; o++) +				setWord(o, partnum, mac[o]); +			part = partnum; +			cmd("setchecksum"); +		} +	} +	return; +invalid_mac_address: +	fprintf(stderr, "Bad MAC address\n"); +	errno = ECANCELED; +	return; +} + +void +cmd(const char *command) +{ +	int c, partnum, part0, part1, row, numInvalid; +	uint8_t *byte; +	uint16_t val16; + +	if (strcmp(command, "dump") == 0) { +		numInvalid = 0; +		for (partnum = 0; partnum < 2; partnum++) { +			if (!validChecksum(partnum)) +				++numInvalid; + +			printf("Part %d:\n", partnum); + +			printf("MAC: "); +			for (c = 0; c < 3; c++) { +				val16 = word(c, partnum); +				byte = (uint8_t *) &val16; +				if (!little_endian) +					byteswap(byte); +				printf("%02x:%02x", byte[0], byte[1]); +				if (c == 2) +					printf("\n"); +				else +					printf(":"); +			} + +			for (row = 0; row < 8; row++) { +				printf("%07x ", row << 4); +				for (c = 0; c < 8; c++) { +					val16 = word((row << 3) + c, partnum); +					byte = (uint8_t *) &val16; +					if (!little_endian) +						byteswap(byte); +					printf("%02x%02x ", byte[1], byte[0]); +				} +				printf("\n"); +			} +		} +		if (numInvalid < 2) { +			errno = 0; +		} +	} else if (strcmp(command, "setchecksum") == 0) { +		val16 = 0; +		for (c = 0; c < 0x3F; c++) +			val16 += word(c, part); +		setWord(0x3F, part, 0xBABA - val16); +	} else if (strcmp(command, "brick") == 0) { +		if (validChecksum(part)) +			setWord(0x3F, part, (word(0x3F, part)) ^ 0xFF); +	} else if (strcmp(command, "swap") == 0) { +		part0 = validChecksum(0); +		part1 = validChecksum(1); +		if ((modified = (part0 | part1))) { +			for(part0 = 0; part0 < SIZE_4KB; part0++) { +				gbe[part0] ^= gbe[part1 = (part0 | SIZE_4KB)]; +				gbe[part1] ^= gbe[part0]; +				gbe[part0] ^= gbe[part1]; +			} +		} +	} else if (strcmp(command, "copy") == 0) { +		if (validChecksum(part)) +			memcpy(gbe + ((part ^ (modified = 1)) << 12), +				gbe + (part << 12), SIZE_4KB); +	} else +		errno = EINVAL; +} + +int +validChecksum(int partnum) +{ +	int w; +	uint16_t total = 0; + +	for(w = 0; w <= 0x3F; w++) +		total += word(w, partnum); + +	if (total != 0xBABA) { +		fprintf(stderr, "BAD checksum in part %d\n", partnum); +		errno = ECANCELED; +		return 0; +	} +	return 1; +} + +uint16_t +word(int pos16, int partnum) +{ +	uint16_t val16 = ((uint16_t *) gbe)[pos16 + (partnum << 11)]; +	if (!little_endian) +		byteswap((uint8_t *) &val16); +	return val16; +} + +void +setWord(int pos16, int partnum, uint16_t val) +{ +	((uint16_t *) gbe)[pos16 + (partnum << 11)] = val; +	if (!little_endian) +		byteswap(gbe + (pos16 << 1) + (partnum << 12)); +	modified = 1; +} + +void +byteswap(uint8_t *byte) { +	byte[0] ^= byte[1]; +	byte[1] ^= byte[0]; +	byte[0] ^= byte[1]; +} | 
