diff --git a/cmd/Kconfig b/cmd/Kconfig index 27086df..cb21dab 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -423,6 +423,12 @@ endmenu menu "Memory commands" +config CMD_BINOP + bool "binop" + help + Compute binary operations (xor, or, and) of byte arrays of arbitrary + size from memory and store the result in memory or the environment. + config CMD_CRC32 bool "crc32" select HASH diff --git a/cmd/Makefile b/cmd/Makefile index 9a358e4..c4269ac 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SOURCE) += source.o obj-$(CONFIG_CMD_SOURCE) += source.o obj-$(CONFIG_CMD_BDI) += bdinfo.o obj-$(CONFIG_CMD_BEDBUG) += bedbug.o +obj-$(CONFIG_CMD_BINOP) += binop.o obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o obj-$(CONFIG_CMD_BMP) += bmp.o obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o diff --git a/cmd/binop.c b/cmd/binop.c new file mode 100644 index 0000000..0002c66 --- /dev/null +++ b/cmd/binop.c @@ -0,0 +1,176 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +enum { + OP_ID_XOR, + OP_ID_AND, + OP_ID_OR, +}; + +void write_to_env_var(char *varname, u8 *result, ulong len) +{ + char *str_output; + char *str_ptr; + int i; + + str_output = malloc(len * 2 + 1); + str_ptr = str_output; + + for (i = 0; i < len; i++) { + sprintf(str_ptr, "%02x", result[i]); + str_ptr += 2; + } + *str_ptr = '\0'; + setenv(varname, str_output); + + free(str_output); +} + +void decode_hexstring(char *hexstr, u8 *result) +{ + int i; + int acc = 0; + + for (i = 0; i < strlen(hexstr); ++i) { + char d = hexstr[i]; + int value; + + if (isdigit(d)) + value = (d - '0'); + else + value = (islower(d) ? toupper(d) : d) - 'A' + 10; + + if (i % 2 == 0) { + acc = value * 16; + } else { + result[i / 2] = acc + value; + acc = 0; + } + } +} + +void read_from_env_var(char *varname, u8 *result) +{ + char *str_value; + + str_value = getenv(varname); + if (str_value) + decode_hexstring(str_value, result); + else + decode_hexstring(varname, result); +} + +void read_from_mem(ulong addr, u8 *result, ulong len) +{ + u8 *src; + + src = map_sysmem(addr, len); + memcpy(result, src, len); + unmap_sysmem(src); +} + +void write_to_mem(char *varname, u8 *result, ulong len) +{ + ulong addr; + u8 *buf; + + addr = simple_strtoul(varname, NULL, 16); + buf = map_sysmem(addr, len); + memcpy(buf, result, len); + unmap_sysmem(buf); +} + +static int do_binop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ulong len; + u8 *result, *src1, *src2; + char *oparg, *lenarg, *src1arg, *src2arg, *destarg; + int i, op; + + if (argc < 5) + return CMD_RET_USAGE; + + oparg = argv[1]; + lenarg = argv[2]; + src1arg = argv[3]; + src2arg = argv[4]; + + if (!strcmp(oparg, "xor")) + op = OP_ID_XOR; + else if (!strcmp(oparg, "or")) + op = OP_ID_OR; + else if (!strcmp(oparg, "and")) + op = OP_ID_AND; + else + return CMD_RET_USAGE; + + len = simple_strtoul(lenarg, NULL, 10); + + src1 = malloc(len); + src2 = malloc(len); + + if (*src1arg == '*') + read_from_mem(simple_strtoul(src1arg + 1, NULL, 16), src1, len); + else + read_from_env_var(src1arg, src1); + + if (*src2arg == '*') + read_from_mem(simple_strtoul(src2arg + 1, NULL, 16), src2, len); + else + read_from_env_var(src2arg, src2); + + result = malloc(len); + + switch (op) { + case OP_ID_XOR: + for (i = 0; i < len; i++) + result[i] = src1[i] ^ src2[i]; + break; + case OP_ID_OR: + for (i = 0; i < len; i++) + result[i] = src1[i] | src2[i]; + break; + case OP_ID_AND: + for (i = 0; i < len; i++) + result[i] = src1[i] & src2[i]; + break; + } + + if (argc == 5) { + for (i = 0; i < len; i++) { + printf("%02x ", result[i]); + if (i % 16 == 15) + puts("\n"); + } + puts("\n"); + + goto exit; + } + + destarg = argv[5]; + + if (*destarg == '*') + write_to_mem(destarg + 1, result, len); /* Skip asterisk */ + else + write_to_env_var(destarg, result, len); +exit: + free(result); + free(src2); + free(src1); + + return 0; +} + +U_BOOT_CMD( + binop, 6, 1, do_binop, + "compute binary operation", + "op count [*]src1 [*]src2 [[*]dest]\n" + " - compute binary operation of data at/in src1 and\n src2 (either *memaddr, env var name or hex string)\n and store result in/at dest, where op is one of\n xor, or, and." +);