#include #include #include #include #include #include #include "crc32.h" #include "mtd.h" #include "fis.h" struct fis_image_hdr { unsigned char name[16]; uint32_t flash_base; uint32_t mem_base; uint32_t size; uint32_t entry_point; uint32_t data_length; } __attribute__((packed)); struct fis_image_crc { uint32_t desc; uint32_t file; } __attribute__((packed)); struct fis_image_desc { struct fis_image_hdr hdr; char _pad[256 - sizeof(struct fis_image_hdr) - sizeof(struct fis_image_crc)]; struct fis_image_crc crc; } __attribute__((packed)); static int fis_fd = -1; static struct fis_image_desc *fis_desc; static int fis_erasesize = 0; static void fis_close(void) { if (fis_desc) munmap(fis_desc, fis_erasesize); if (fis_fd >= 0) close(fis_fd); fis_fd = -1; fis_desc = NULL; } static struct fis_image_desc * fis_open(void) { struct fis_image_desc *desc; if (fis_fd >= 0) fis_close(); fis_fd = mtd_check_open("FIS directory"); if (fis_fd < 0) goto error; close(fis_fd); fis_fd = mtd_open("FIS directory", true); if (fis_fd < 0) goto error; fis_erasesize = erasesize; desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED, fis_fd, 0); if (desc == MAP_FAILED) goto error; fis_desc = desc; return desc; error: fis_close(); return NULL; } int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new) { struct fis_image_desc *desc; void *end; int found = 0; int i; desc = fis_open(); if (!desc) return 0; for (i = 0; i < n_new - 1; i++) { if (!new[i].size) { fprintf(stderr, "FIS error: only the last partition can detect the size automatically\n"); i = -1; goto done; } } end = desc; end = (char *) end + fis_erasesize; while ((void *) desc < end) { if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff)) break; for (i = 0; i < n_old; i++) { if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) { found++; goto next; } } next: desc++; continue; } if (found == n_old) i = 1; else i = -1; done: fis_close(); return i; } int fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new) { struct fis_image_desc *fisdir = NULL; struct fis_image_desc *redboot = NULL; struct fis_image_desc *first = NULL; struct fis_image_desc *last = NULL; struct fis_image_desc *desc; struct fis_part *part; uint32_t offset = 0, size = 0; char *end, *tmp; int i; desc = fis_open(); if (!desc) return -1; if (!quiet) fprintf(stderr, "Updating FIS table... \n"); end = (char *) desc + fis_erasesize; while ((char *) desc < end) { if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff)) break; if (!strcmp((char *) desc->hdr.name, "FIS directory")) fisdir = desc; if (!strcmp((char *) desc->hdr.name, "RedBoot")) redboot = desc; for (i = 0; i < n_old; i++) { if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) { size += desc->hdr.size; last = desc; if (!first) first = desc; break; } } desc++; } desc--; if (desc == last) { desc = fisdir; } /* size fixup */ if (desc && (last->hdr.flash_base < desc->hdr.flash_base - last->hdr.size)) size += (desc->hdr.flash_base - last->hdr.flash_base) - last->hdr.size; #ifdef notyet desc = first - 1; if (redboot && (desc >= redboot)) { if (first->hdr.flash_base - desc->hdr.size > desc->hdr.flash_base) { int delta = first->hdr.flash_base - desc->hdr.size - desc->hdr.flash_base; offset -= delta; size += delta; } } #endif last++; desc = first + n_new; offset = first->hdr.flash_base; if (desc != last) { if (desc > last) tmp = (char *) desc; else tmp = (char *) last; memmove(desc, last, end - tmp); if (desc < last) { tmp = end - (last - desc) * sizeof(struct fis_image_desc); memset(tmp, 0xff, tmp - end); } } for (part = new, desc = first; desc < first + n_new; desc++, part++) { memset(desc, 0, sizeof(struct fis_image_desc)); memcpy(desc->hdr.name, part->name, sizeof(desc->hdr.name)); desc->crc.desc = 0; desc->crc.file = 0; desc->hdr.flash_base = offset; desc->hdr.mem_base = part->loadaddr; desc->hdr.entry_point = part->loadaddr; desc->hdr.size = (part->size > 0) ? part->size : size; desc->hdr.data_length = desc->hdr.size; offset += desc->hdr.size; size -= desc->hdr.size; } msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE); fis_close(); return 0; }