mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-19 07:16:16 +02:00
dd97bbee8a
When mtd alters the fis partition table it assumes that the first partition table entry also is the first logical parition table entry. For instance our table could look like this (irrelevant partitions put aside): * vmlinux.bin.l7 0xA8710000 * rootfs 0xA8030000 Here mtd would assume vmlinux.bin.l7 being the first partition and use its address to calculate the size and offset which ultimately leads to a broken partition table. This patch alters the behavior by checking what partition has the smaller address to do the calculations based on that address. Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@32601 3c298f89-4303-0410-b956-a3cf2f4a3e73
263 lines
5.4 KiB
C
263 lines
5.4 KiB
C
/*
|
|
* FIS table updating code for mtd
|
|
*
|
|
* Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License v2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#include <sys/mman.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#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|MAP_LOCKED, 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 -1;
|
|
|
|
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 *first_fb = NULL;
|
|
struct fis_image_desc *last_fb = NULL;
|
|
struct fis_image_desc *desc;
|
|
struct fis_part *part;
|
|
uint32_t offset = 0, size = 0;
|
|
char *start, *end, *tmp;
|
|
int i;
|
|
|
|
desc = fis_open();
|
|
if (!desc)
|
|
return -1;
|
|
|
|
if (!quiet)
|
|
fprintf(stderr, "Updating FIS table... \n");
|
|
|
|
start = (char *) desc;
|
|
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;
|
|
|
|
/* update max offset */
|
|
if (offset < desc->hdr.flash_base)
|
|
offset = desc->hdr.flash_base;
|
|
|
|
for (i = 0; i < n_old; i++) {
|
|
if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
|
|
last = desc;
|
|
if (!first)
|
|
first = desc;
|
|
break;
|
|
}
|
|
}
|
|
desc++;
|
|
}
|
|
desc--;
|
|
|
|
first_fb = first;
|
|
last_fb = last;
|
|
|
|
if (first_fb->hdr.flash_base > last_fb->hdr.flash_base) {
|
|
first_fb = last;
|
|
last_fb = first;
|
|
}
|
|
|
|
/* determine size of available space */
|
|
desc = (struct fis_image_desc *) start;
|
|
while ((char *) desc < end) {
|
|
if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
|
|
break;
|
|
|
|
if (desc->hdr.flash_base > last_fb->hdr.flash_base &&
|
|
desc->hdr.flash_base < offset)
|
|
offset = desc->hdr.flash_base;
|
|
|
|
desc++;
|
|
}
|
|
desc--;
|
|
|
|
size = offset - first_fb->hdr.flash_base;
|
|
|
|
#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_fb->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;
|
|
}
|