From 81df5de5edc5498157e61fac3a0540cc36714ef3 Mon Sep 17 00:00:00 2001 From: Oyvind Repvik Date: Fri, 16 Mar 2007 18:07:30 +0000 Subject: fis: Add utility for parsing/editing a Redboot FIS partition layout from userspace --- packages/fis/files/.mtn2git_empty | 0 packages/fis/files/fis.cc | 372 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+) create mode 100644 packages/fis/files/.mtn2git_empty create mode 100644 packages/fis/files/fis.cc (limited to 'packages/fis/files') diff --git a/packages/fis/files/.mtn2git_empty b/packages/fis/files/.mtn2git_empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/fis/files/fis.cc b/packages/fis/files/fis.cc new file mode 100644 index 0000000000..8c43eca811 --- /dev/null +++ b/packages/fis/files/fis.cc @@ -0,0 +1,372 @@ +// fis.cc +// see http://svn.chezphil.org/utils +// (C) 2007 Philip Endecott + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#include +#include +#include + +#include +#include + +#include "Exception.hh" +#include "FileDescriptor.hh" +#include "utils.hh" +#include "endian.hh" + +#include + +using namespace std; +using namespace boost; +using namespace pbe; + + +static void check_dev(string device) +{ + if (device=="") { + throw "You must specify a device using -d"; + } +} + + +// This is taken from drivers/mtd/redboot.c in the Linux source +struct fis_image_desc { + char name[16]; // Null terminated name + uint32_t flash_base; // Address within FLASH of image + uint32_t mem_base; // Address in memory where it executes + uint32_t size; // Length of image + uint32_t entry_point; // Execution entry point + uint32_t data_length; // Length of actual data + uint32_t skips[53]; + uint32_t desc_cksum; // Checksum over image descriptor + uint32_t file_cksum; // Checksum over image data +}; + +ostream& operator<<(ostream& strm, const fis_image_desc& d) +{ + strm << format("%16s: addr = 0x%08x, size = 0x%08x\n") + % (d.name) % (d.flash_base) % (d.size); + for (unsigned int i=0; i<(sizeof(d.skips)/4); ++i) { + if (d.skips[i]==0x736b6970 || d.skips[i]==0x70696b73) { // "skip" + uint32_t offset = d.skips[i+1]; + uint32_t length = d.skips[i+2]; + strm << format(" skip: %08x + %08x\n") + % (offset) % (length); + i+=2; + } + } + return strm; +} + + +void check_checksum(const fis_image_desc& d) +{ + // This isn't checked by the kernel mtd driver, which has this + // comment: "RedBoot doesn't actually write the desc_cksum field yet + // AFAICT". I don't know what checksum is supposed to be used here. +} + +void compute_checksum(fis_image_desc& d) +{ + // ditto +} + + +typedef map dir_t; + + +static void swap_entry_endianness(fis_image_desc& d) +{ + d.flash_base = swap_end_32(d.flash_base); + d.mem_base = swap_end_32(d.mem_base); + d.size = swap_end_32(d.size); + d.entry_point = swap_end_32(d.entry_point); + d.data_length = swap_end_32(d.data_length); + for (unsigned int i=0; i<(sizeof(d.skips)/4); ++i) { + d.skips[i] = swap_end_32(d.skips[i]); + } +} + + +static void load_dir(FileDescriptor& fd, int offset, int size, bool swap_endianness, + dir_t& dir) +{ + fd.seek(offset); + int num_entries = size/sizeof(fis_image_desc); + for (int i=0; i(); + if (d.name[0]!=static_cast(0xff)) { + check_checksum(d); + if (swap_endianness) { + swap_entry_endianness(d); + } + dir[d.flash_base] = d; + } + } +} + + +static void write_blank_entries(FileDescriptor& fd, int n) +{ + char dummy[sizeof(fis_image_desc)]; + for (unsigned int i=0; isecond; + compute_checksum(d); + if (swap_endianness) { + swap_entry_endianness(d); + } + fd.binwrite(d); + } + write_blank_entries(fd,num_entries-dir.size()); +} + + +static void fis_list(string device, int offset, int size, bool swap_endianness) +{ + FileDescriptor fd(device,FileDescriptor::read_only); + dir_t dir; + load_dir(fd,offset,size,swap_endianness,dir); + for (dir_t::const_iterator i = dir.begin(); + i != dir.end(); ++i) { + cout << i->second; + } +} + + +static void fis_init(string device, int offset, int size) +{ + FileDescriptor fd(device,FileDescriptor::create); + fd.seek(offset); + int num_entries = size/sizeof(fis_image_desc); + write_blank_entries(fd,num_entries); +} + + +static void check_overlap(const dir_t& dir, uint32_t addr, uint32_t size) +{ + uint32_t end_addr = addr+size; + for (dir_t::const_iterator i = dir.begin(); + i != dir.end(); ++i) { + if (addr<(i->second.flash_base+i->second.size) + && end_addr>i->second.flash_base) { + throw "New partition overlaps existing partitions"; + } + } +} + + +static void fis_create(string device, int offset, int size, bool swap_endianness, + int argc, char* argv[]) +{ + fis_image_desc d; + d.mem_base = 0; + d.entry_point = 0; + d.data_length = 0; + for (unsigned int i=0; i<(sizeof(d.skips)/4); ++i) { + d.skips[i] = 0; + } + d.desc_cksum = 0; + d.file_cksum = 0; + + for (int i=0; i=16) { + throw "name too long, max 16 chars including terminating null"; + } + for (int j=0; j<16; j++) { + char c = name.c_str()[j]; + d.name[j] = c; + if (!c) { + for (; j<16; ++j) { + d.name[j]=0; + } + break; + } + } + } else { + cerr << "Unrecognised option '" << arg << "'\n"; + exit(1); + } + } + + FileDescriptor fd(device,FileDescriptor::read_write); + dir_t dir; + load_dir(fd,offset,size,swap_endianness,dir); + check_overlap(dir,d.flash_base,d.size); + dir[d.flash_base] = d; + save_dir(fd,offset,size,swap_endianness,dir); +} + + +static void fis_delete(string device, int offset, int size, bool swap_endianness, + string name) +{ + FileDescriptor fd(device,FileDescriptor::read_write); + dir_t dir; + load_dir(fd,offset,size,swap_endianness,dir); + + for (dir_t::iterator i = dir.begin(); + i != dir.end(); ++i) { + string this_name(i->second.name); + if (this_name == name) { + dir.erase(i); + save_dir(fd,offset,size,swap_endianness,dir); + return; + } + } + + throw "No partition found with specified name"; +} + + +static void usage() +{ + cerr << "Usage:\n" + << " fis [options] list\n" + << " fis [options] init\n" + << " fis [options] create -f address -l size -n name\n" + << " fis [options] delete name\n" + << "Options:\n" + << " -d device specify /dev/mtd* device containing directory\n" + << " -o offset specify offset into device of start of directory\n" + << " (in decimal; prefix with 0x for hex)\n" + << " -s size specify size of directory in bytes\n" + << " -e swap endianness\n"; +} + + +int main(int argc, char* argv[]) +{ + try { try { + + if (argc==1) { + usage(); + exit(1); + } + + string device=""; + int offset=0; + int size=0; + bool swap_endianness=false; + + for (int i=1; i