// 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. #define BOOST_SP_DISABLE_THREADS #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