summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/imd.c2
-rw-r--r--common/Kconfig1
-rw-r--r--common/imd-barebox.c1
-rw-r--r--common/imd.c152
-rw-r--r--include/image-metadata.h38
-rw-r--r--scripts/bareboximd.c34
6 files changed, 226 insertions, 2 deletions
diff --git a/commands/imd.c b/commands/imd.c
index f1a22cef96..fc6cc47231 100644
--- a/commands/imd.c
+++ b/commands/imd.c
@@ -46,6 +46,8 @@ BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT ("-t <type>", "only show information of <type>")
BAREBOX_CMD_HELP_OPT ("-n <no>", "for tags with multiple strings only show string <no>")
BAREBOX_CMD_HELP_OPT ("-s VARNAME", "set variable VARNAME instead of showing information")
+BAREBOX_CMD_HELP_OPT ("-V", "Verify checksum of FILE")
+BAREBOX_CMD_HELP_OPT ("-c", "Create checksum for FILE and write it to the crc32 tag.")
BAREBOX_CMD_HELP_TEXT("")
BAREBOX_CMD_HELP_TEXT("Without options all information available is printed. Valid types are:")
BAREBOX_CMD_HELP_TEXT("release, build, model, of_compatible")
diff --git a/common/Kconfig b/common/Kconfig
index f9ef9bd83b..fcdeb5c30b 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -693,6 +693,7 @@ config FLEXIBLE_BOOTARGS
completely.
config IMD
+ select CRC32
bool "barebox metadata support"
config IMD_TARGET
diff --git a/common/imd-barebox.c b/common/imd-barebox.c
index e9cd37d83e..e5cdfd1aed 100644
--- a/common/imd-barebox.c
+++ b/common/imd-barebox.c
@@ -23,3 +23,4 @@ __BAREBOX_IMD_SECTION(.barebox_imd_end) = {
BAREBOX_IMD_TAG_STRING(imd_build_tag, IMD_TYPE_BUILD, UTS_VERSION, 1);
BAREBOX_IMD_TAG_STRING(imd_release_tag, IMD_TYPE_RELEASE, UTS_RELEASE, 1);
+BAREBOX_IMD_CRC(imd_crc32, 0x0, 1);
diff --git a/common/imd.c b/common/imd.c
index e0dab69644..9be07fef74 100644
--- a/common/imd.c
+++ b/common/imd.c
@@ -22,6 +22,7 @@
#include <getopt.h>
#include <malloc.h>
#include <fs.h>
+#include <crc.h>
#ifndef CONFIG_CMD_IMD
int imd_command_setenv(const char *variable_name, const char *value)
@@ -167,6 +168,9 @@ static struct imd_type_names imd_types[] = {
}, {
.type = IMD_TYPE_OF_COMPATIBLE,
.name = "of_compatible",
+ }, {
+ .type = IMD_TYPE_CRC32,
+ .name = "crc32",
},
};
@@ -257,6 +261,23 @@ char *imd_concat_strings(const struct imd_header *imd)
}
/**
+ * imd_uint32_flags - get uint32 flags
+ * @imd: The IMD entry
+ *
+ * This function returns the flags in @imd.
+ *
+ * Return: A pointer to the flags or NULL if the entry is not uint32.
+ */
+static uint32_t *imd_crc32_flags(const struct imd_header *imd) {
+ char *p = (char *)(imd + 1);
+
+ if (!imd_is_crc32(imd_read_type(imd)))
+ return NULL;
+
+ return (uint32_t *)(p + sizeof(uint32_t));
+}
+
+/**
* imd_get_param - get a parameter
* @imd: The IMD entry
* @name: The name of the parameter.
@@ -287,6 +308,118 @@ const char *imd_get_param(const struct imd_header *imd, const char *name)
return NULL;
}
+static int imd_calculate_crc32(void *input, const struct imd_header *imd_start,
+ struct imd_header **imd_crc, uint32_t *crc,
+ size_t size)
+{
+ const struct imd_header *imd;
+ int length;
+ int end_ofs = (char *)imd_start - (char *)input + sizeof(char) * 8;
+
+ /* search the checksum imd token */
+ imd_for_each(imd_start, imd) {
+ length = imd_read_length(imd);
+ length = ALIGN(length, 4);
+ length += sizeof(struct imd_header);
+
+ if (imd_read_type(imd) == IMD_TYPE_CRC32) {
+ *imd_crc = (struct imd_header *)imd;
+ debug("Found crc token at %d\n", end_ofs);
+ break;
+ }
+
+ end_ofs += length;
+ }
+
+ /*
+ * Calculate checksum from start of input up to the checksum.
+ * The checksum and the flags field in the imd_entry_crc32 entry are
+ * modified after the checksum is calculated. Therefore skip them here
+ * or the checksum will become invalid once it is written to the
+ * checksum tag.
+ */
+ length = sizeof(struct imd_header);
+ end_ofs += length;
+
+ *crc = crc32(*crc, input, end_ofs);
+ debug("Calculated checksum from %d to %d: 0x%08x\n", 0, end_ofs, *crc);
+
+ /* move past the checksum data and flags field */
+ end_ofs += sizeof(uint32_t) + sizeof(char);
+ input += end_ofs;
+
+ *crc = crc32(*crc, input, size - end_ofs);
+ debug("Calculated checksum from %d to %d: 0x%08x\n", end_ofs,
+ end_ofs + (size - end_ofs), *crc);
+
+ return 0;
+}
+
+static int imd_write_crc32(void *buf, const struct imd_header *imd_start,
+ const char *filename, size_t size)
+{
+ struct imd_header *imd_crc;
+ uint32_t crc = 0;
+
+ imd_calculate_crc32(buf, imd_start, &imd_crc, &crc, size);
+ debug("Calculated crc: 0x%08x\n", crc);
+
+ if (!imd_crc) {
+ debug("No tag of type 0x%08x found\n", IMD_TYPE_CRC32);
+
+ return -ENODATA;
+ } else {
+ uint32_t *p = (uint32_t *)(imd_crc + 1);
+
+ if (*p != crc) {
+ uint32_t *flags = imd_crc32_flags(imd_crc);
+ *flags |= IMD_CRC32_FLAG_TAG_VALID;
+ debug("Update crc token from 0x%08x to 0x%08x (flags 0x%08x)\n", *p, crc, *flags);
+ *p = crc;
+
+ write_file(filename, buf, size);
+ }
+ }
+
+ return 0;
+};
+
+int imd_verify_crc32(void *buf, size_t size)
+{
+ const struct imd_header *imd_start;
+ struct imd_header *imd_crc;
+ uint32_t crc = 0;
+
+ imd_start = imd_get(buf, size);
+ if (IS_ERR(imd_start))
+ return PTR_ERR(imd_start);
+
+ imd_calculate_crc32(buf, imd_start, &imd_crc, &crc, size);
+ debug("Calculated crc: 0x%08x\n", crc);
+
+ if (!imd_crc) {
+ debug("No tag of type 0x%08x found\n", IMD_TYPE_CRC32);
+
+ return -ENOENT;
+ } else {
+ uint32_t *p = (uint32_t *)(imd_crc + 1);
+ uint32_t *flags = imd_crc32_flags(imd_crc);
+
+ if (*p != crc && imd_crc32_is_valid(*flags)) {
+ eprintf("CRC: image corrupted. Found checksum 0x%08x instead of 0x%08x\n",
+ *p, crc);
+ return -EILSEQ;
+ } else if (*p != crc && !imd_crc32_is_valid(*flags)) {
+ printf("CRC: is invalid, but the checksum tag is not enabled\n");
+ return -EINVAL;
+ } else {
+ printf("CRC: valid\n");
+ }
+ }
+
+ return 0;
+};
+
int imd_command_verbose;
int imd_command(int argc, char *argv[])
@@ -299,10 +432,12 @@ int imd_command(int argc, char *argv[])
const char *filename;
const char *variable_name = NULL;
char *str;
+ uint32_t checksum = 0;
+ uint32_t verify = 0;
imd_command_verbose = 0;
- while ((opt = getopt(argc, argv, "vt:s:n:")) > 0) {
+ while ((opt = getopt(argc, argv, "vt:s:n:cV")) > 0) {
switch(opt) {
case 't':
type = imd_name_to_type(optarg);
@@ -320,6 +455,12 @@ int imd_command(int argc, char *argv[])
case 'n':
strno = simple_strtoul(optarg, NULL, 0);
break;
+ case 'c':
+ checksum = 1;
+ break;
+ case 'V':
+ verify = 1;
+ break;
default:
return -ENOSYS;
}
@@ -342,6 +483,11 @@ int imd_command(int argc, char *argv[])
goto out;
}
+ if (checksum)
+ imd_write_crc32(buf, imd_start, filename, size);
+ if (verify)
+ imd_verify_crc32(buf, size);
+
if (type == IMD_TYPE_INVALID) {
imd_for_each(imd_start, imd) {
uint32_t type = imd_read_type(imd);
@@ -350,6 +496,10 @@ int imd_command(int argc, char *argv[])
str = imd_concat_strings(imd);
printf("%s: %s\n", imd_type_to_name(type), str);
+ } else if (imd_is_crc32(type)) {
+ uint32_t *p = (uint32_t *)(imd + 1);
+
+ printf("%s: 0x%08x\n", imd_type_to_name(type), *p);
} else {
debug("Unknown tag 0x%08x\n", type);
}
diff --git a/include/image-metadata.h b/include/image-metadata.h
index 5904d95acd..4ed5448a8c 100644
--- a/include/image-metadata.h
+++ b/include/image-metadata.h
@@ -25,9 +25,12 @@
#define IMD_TYPE_MODEL 0x640c8004 /* The board name this image is for */
#define IMD_TYPE_OF_COMPATIBLE 0x640c8005 /* the device tree compatible string */
#define IMD_TYPE_PARAMETER 0x640c8006 /* A generic parameter. Use key=value as data */
+#define IMD_TYPE_CRC32 0x640c1007 /* the checksum of the barebox images */
#define IMD_TYPE_END 0x640c7fff
#define IMD_TYPE_INVALID 0xffffffff
+#define IMD_CRC32_FLAG_TAG_VALID (1 << 0)
+
/*
* The IMD header. All data is stored in little endian format in the image.
* The next header starts at the next 4 byte boundary after the data.
@@ -51,8 +54,26 @@ static inline int imd_is_string(uint32_t type)
return (type & 0x8000) ? 1 : 0;
}
-static inline int imd_type_valid(uint32_t type)
+/*
+ * A IMD int.
+ */
+struct imd_entry_crc32 {
+ struct imd_header header;
+ uint32_t data;
+ uint32_t flags;
+};
+
+static inline int imd_is_crc32(uint32_t type)
+{
+ return (type & IMD_TYPE_CRC32) ? 1 : 0;
+}
+
+static inline int imd_crc32_is_valid(uint32_t flags)
{
+ return (flags & IMD_CRC32_FLAG_TAG_VALID) ? 1 : 0;
+}
+
+static inline int imd_type_valid(uint32_t type) {
return (type & 0xffff0000) == 0x640c0000;
}
@@ -78,11 +99,18 @@ static inline uint32_t imd_read_length(const struct imd_header *imd)
return imd_read_le32(&imd->datalength);
}
+static inline uint32_t imd_read_flags(const struct imd_entry_crc32 *imd)
+{
+ return imd_read_le32(&imd->flags);
+}
+
const struct imd_header *imd_find_type(const struct imd_header *imd,
uint32_t type);
const struct imd_header *imd_get(const void *buf, int size);
const char *imd_string_data(const struct imd_header *imd, int index);
+const uint32_t *imd_uint32_data(const struct imd_header *imd);
+uint32_t *imd_uint32_flags(const struct imd_header *imd);
const char *imd_type_to_name(uint32_t type);
char *imd_concat_strings(const struct imd_header *imd);
const char *imd_get_param(const struct imd_header *imd, const char *name);
@@ -90,6 +118,7 @@ const char *imd_get_param(const struct imd_header *imd, const char *name);
extern int imd_command_verbose;
int imd_command_setenv(const char *variable_name, const char *value);
int imd_command(int argc, char *argv[]);
+int imd_verify_crc32(void *buf, size_t size);
#ifdef __BAREBOX__
@@ -107,6 +136,13 @@ int imd_command(int argc, char *argv[]);
.data = _string, \
}
+#define BAREBOX_IMD_CRC(_name, _crc, _keep_if_unused) \
+ const struct imd_entry_crc32 __barebox_imd_##__name \
+ __BAREBOX_IMD_SECTION(.barebox_imd_ ## _keep_if_unused ## _ ## _name) = { \
+ .header.type = cpu_to_le32(IMD_TYPE_CRC32), \
+ .header.datalength = cpu_to_le32(sizeof(uint32_t) * 2), \
+ .data = _crc, \
+ }
#ifdef CONFIG_IMD
void imd_used(const void *);
diff --git a/scripts/bareboximd.c b/scripts/bareboximd.c
index 5ef91831c4..cf1b8f693a 100644
--- a/scripts/bareboximd.c
+++ b/scripts/bareboximd.c
@@ -33,6 +33,7 @@
#include <errno.h>
#include <stdarg.h>
#include <linux/err.h>
+#include <linux/kernel.h>
#include "../include/image-metadata.h"
@@ -57,6 +58,35 @@ int imd_command_setenv(const char *variable_name, const char *value)
return -EINVAL;
}
+static int write_file(const char *filename, const void *buf, size_t size)
+{
+ int fd, ret;
+ int now;
+
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT);
+ if (fd < 0)
+ return fd;
+
+ while (size) {
+ now = write(fd, buf, size);
+ if (now == 0) {
+ errno = ENOSPC;
+ return -1;
+ }
+ if (now < 0)
+ return now;
+ size -= now;
+ buf += now;
+ }
+
+ close(fd);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_size)
{
off_t fsize;
@@ -129,6 +159,8 @@ static unsigned long simple_strtoul(const char *cp, char **endp, unsigned int ba
return strtoul(cp, endp, base);
}
+#include "../include/xfuncs.h"
+#include "../crypto/crc32.c"
#include "../common/imd.c"
static void usage(const char *prgname)
@@ -140,6 +172,8 @@ static void usage(const char *prgname)
"Options:\n"
"-t <type> only show information of <type>\n"
"-n <no> for tags with multiple strings only show string <no>\n"
+"-V Verify checksum of FILE\n"
+"-c Create checksum for FILE and write it to the crc32 tag\n"
"\n"
"Without options all information available is printed. Valid types are:\n"
"release, build, model, of_compatible\n",