summaryrefslogtreecommitdiff
path: root/futility/cmd_validate_rec_mrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'futility/cmd_validate_rec_mrc.c')
-rw-r--r--futility/cmd_validate_rec_mrc.c95
1 files changed, 76 insertions, 19 deletions
diff --git a/futility/cmd_validate_rec_mrc.c b/futility/cmd_validate_rec_mrc.c
index 3013891a..1fdd47c1 100644
--- a/futility/cmd_validate_rec_mrc.c
+++ b/futility/cmd_validate_rec_mrc.c
@@ -35,19 +35,22 @@ static void print_help(int argc, char *argv[])
printf("\n");
}
-struct mrc_cache {
+struct mrc_metadata {
uint32_t signature;
- uint32_t size;
- uint32_t checksum;
+ uint32_t data_size;
+ uint16_t data_checksum;
+ uint16_t header_checksum;
uint32_t version;
- uint8_t data[0];
} __attribute__((packed));
#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24))
+#define REGF_BLOCK_SHIFT 4
+#define REGF_UNALLOCATED_BLOCK 0xffff
-unsigned long compute_ip_checksum(void *addr, unsigned long length)
+
+unsigned long compute_ip_checksum(const void *addr, unsigned long length)
{
- uint8_t *ptr;
+ const uint8_t *ptr;
volatile union {
uint8_t byte[2];
uint16_t word;
@@ -77,29 +80,71 @@ unsigned long compute_ip_checksum(void *addr, unsigned long length)
return (~value.word) & 0xFFFF;
}
-static int verify_checksum(struct mrc_cache *cache, unsigned long cache_len)
+static int verify_mrc_slot(struct mrc_metadata *md, unsigned long slot_len)
{
- uint32_t checksum;
- if (cache->signature != MRC_DATA_SIGNATURE) {
+ uint32_t header_checksum;
+ if (md->signature != MRC_DATA_SIGNATURE) {
fprintf(stderr, "MRC signature mismatch\n");
return 1;
}
fprintf(stderr, "MRC signature match.. successful\n");
- if (cache->size > cache_len) {
+ if (md->data_size > slot_len) {
fprintf(stderr, "MRC cache size overflow\n");
return 1;
}
- checksum = compute_ip_checksum((void *)&cache->data[0], cache->size);
+ header_checksum = md->header_checksum;
+ md->header_checksum = 0;
+
+ if (header_checksum != compute_ip_checksum(md, sizeof(*md))) {
+ fprintf(stderr, "MRC metadata header checksum mismatch\n");
+ return 1;
+ }
+
+ md->header_checksum = header_checksum;
+
+ fprintf(stderr, "MRC metadata header checksum.. verified!\n");
- if (checksum != cache->checksum) {
- fprintf(stderr, "MRC checksum mismatch\n");
+ if (md->data_checksum != compute_ip_checksum(&md[1], md->data_size)) {
+ fprintf(stderr, "MRC data checksum mismatch\n");
+ return 1;
+ }
+
+ fprintf(stderr, "MRC data checksum.. verified!\n");
+ return 0;
+}
+
+static int get_mrc_data_slot(uint16_t *mb, uint32_t *data_offset,
+ uint32_t *data_size)
+{
+ /*
+ * First block offset in metadata block tells the total number of
+ * metadata blocks.
+ * Currently, we expect only 1 metadata block to be present.
+ */
+ if (*mb != 1) {
+ fprintf(stderr, "Only 1 metadata block is expected. "
+ "Actual %x\n", *mb);
+ return 1;
+ }
+
+ /*
+ * RECOVERY_MRC_CACHE is expected to contain only one slot. Thus, there
+ * should be only one block offset present, indicating size of the MRC
+ * cache slot.
+ */
+ mb++;
+ *data_offset = (1 << REGF_BLOCK_SHIFT);
+ *data_size = (*mb - 1) << REGF_BLOCK_SHIFT;
+
+ mb++;
+ if (*mb != REGF_UNALLOCATED_BLOCK) {
+ fprintf(stderr, "More than 1 slot in recovery mrc cache.\n");
return 1;
}
- fprintf(stderr, "MRC checksum.. verified!\n");
return 0;
}
@@ -111,6 +156,8 @@ static int do_validate_rec_mrc(int argc, char *argv[])
uint32_t file_size;
uint8_t *buff;
uint32_t offset = 0;
+ uint32_t data_offset;
+ uint32_t data_size;
char *e;
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
@@ -162,12 +209,22 @@ static int do_validate_rec_mrc(int argc, char *argv[])
return 1;
}
- if (file_size > offset)
- ret = verify_checksum((struct mrc_cache *)(buff + offset),
- file_size - offset);
+ if (get_mrc_data_slot((uint16_t *)(buff + offset), &data_offset,
+ &data_size)) {
+ fprintf(stderr, "Metadata block error\n");
+ futil_unmap_file(fd, MAP_RO, buff, file_size);
+ close(fd);
+ return 1;
+ }
+ offset += data_offset;
+
+ if ((file_size > offset) && ((file_size - offset) >= data_size))
+ ret = verify_mrc_slot((struct mrc_metadata *)(buff + offset),
+ data_size);
else
- fprintf(stderr, "Offset greater than file size: offset=0x%x, "
- "file size=0x%x\n", offset, file_size);
+ fprintf(stderr, "Offset or data size greater than file size: "
+ "offset=0x%x, file size=0x%x, data_size=0x%x\n",
+ offset, file_size, data_size);
if (futil_unmap_file(fd, MAP_RO, buff, file_size) != FILE_ERR_NONE) {
fprintf(stderr, "Failed to unmap file %s\n", infile);