/*
EIBD eib bus access and management daemon
Copyright (C) 2005-2007 Martin Koegler <mkoegler@auto.tuwien.ac.at>
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
(at your option) 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 "loadimage.h"
#include "image.h"
static void
GenAlloc (CArray & req, uint16_t start, uint16_t len, uint8_t access,
uint8_t type, bool check)
{
const uchar zero[10] = { 0 };
req.set (zero, 10);
req[0] = 0x03;
req[2] = (start >> 8) & 0xff;
req[3] = (start) & 0xff;
req[4] = (len >> 8) & 0xff;
req[5] = (len) & 0xff;
req[6] = access;
req[7] = type;
req[8] = check ? 0x80 : 0x00;
}
typedef struct
{
uint16_t start;
uint16_t len;
} Segment;
static int
AddSegmentOverlap (Array < Segment > &s, uint16_t start, uint16_t len)
{
int i;
if (!len)
return 1;
for (i = 0; i < s (); i++)
{
if (start >= s[i].start && start < s[i].start + s[i].len)
return 0;
if (s[i].start >= start && s[i].start < start + len)
return 0;
}
Segment s1;
s1.start = start;
s1.len = len;
if (len)
s.add (s1);
return 1;
}
BCU_LOAD_RESULT
PrepareLoadImage (const CArray & im, BCUImage * &img)
{
Array < Segment > seg;
img = 0;
Image *i = Image::fromArray (im);
if (!i)
return IMG_UNRECOG_FORMAT;
if (!i->isValid ())
{
delete i;
return IMG_INVALID_FORMAT;
}
STR_BCUType *b = (STR_BCUType *) i->findStream (S_BCUType);
if (!b)
{
delete i;
return IMG_NO_BCUTYPE;
}
STR_Code *c = (STR_Code *) i->findStream (S_Code);
if (!c)
{
delete i;
return IMG_NO_CODE;
}
if (b->bcutype == 0x0012)
{
STR_BCU1Size *s = (STR_BCU1Size *) i->findStream (S_BCU1Size);
if (!s)
{
delete i;
return IMG_NO_SIZE;
}
if (s->datasize + s->bsssize + s->stacksize > 18)
{
delete i;
return IMG_LODATA_OVERFLOW;
}
if (s->textsize > 0xfe)
{
delete i;
return IMG_TEXT_OVERFLOW;
}
if (s->textsize != c->code ())
{
delete i;
return IMG_WRONG_SIZE;
}
if (s->textsize < 0x18)
{
delete i;
return IMG_NO_ADDRESS;
}
if (c->code[8] < 8 || c->code[8] > c->code () + 1)
{
delete i;
return IMG_WRONG_CHECKLIM;
}
img = new BCUImage;
img->code = c->code;
img->BCUType = BCUImage::B_bcu1;
img->addr = (c->code[0x17] << 8) | (c->code[0x18]);
return IMG_IMAGE_LOADABLE;
}
if (b->bcutype == 0x0020 || b->bcutype == 0x0021)
{
STR_BCU2Size *s = (STR_BCU2Size *) i->findStream (S_BCU2Size);
if (!s)
{
delete i;
return IMG_NO_SIZE;
}
if (s->lo_datasize + s->lo_bsssize > 18)
{
delete i;
return IMG_LODATA_OVERFLOW;
}
if (s->hi_datasize + s->hi_bsssize > 24)
{
delete i;
return IMG_HIDATA_OVERFLOW;
}
if (s->textsize > 0x36f)
{
delete i;
return IMG_TEXT_OVERFLOW;
}
if (s->textsize != c->code ())
{
delete i;
return IMG_WRONG_SIZE;
}
if (s->textsize < 0x18)
{
delete i;
return IMG_NO_ADDRESS;
}
STR_BCU2Start *s1 = (STR_BCU2Start *) i->findStream (S_BCU2Start);
if (!s1)
{
delete i;
return IMG_NO_START;
}
if (s1->addrtab_start != 0x116 || s1->addrtab_size < 4)
{
delete i;
return IMG_WRONG_ADDRTAB;
}
if (s1->addrtab_size > 0xff)
{
delete i;
return IMG_ADDRTAB_OVERFLOW;
}
AddSegmentOverlap (seg, s1->addrtab_start, s1->addrtab_size);
if (!AddSegmentOverlap (seg, s1->assoctab_start, s1->assoctab_size))
{
delete i;
return IMG_OVERLAP_ASSOCTAB;
}
if (s1->assoctab_size > 0xff)
{
delete i;
return IMG_ADDRTAB_OVERFLOW;
}
if (s1->readonly_end < s1->readonly_start)
{
delete i;
return IMG_NEGATIV_TEXT_SIZE;
}
if (!AddSegmentOverlap
(seg, s1->readonly_start, s1->readonly_end - s1->readonly_start))
{
delete i;
return IMG_OVERLAP_TEXT;
}
if (s1->param_end < s1->param_start)
{
delete i;
return IMG_NEGATIV_TEXT_SIZE;
}
if (s1->eeprom_end < s1->eeprom_start)
{
delete i;
return IMG_NEGATIV_TEXT_SIZE;
}
if (!AddSegmentOverlap
(seg, s1->eeprom_start, s1->eeprom_end - s1->eeprom_start))
{
delete i;
return IMG_OVERLAP_EEPROM;
}
if (!AddSegmentOverlap
(seg, s1->param_start, s1->param_end - s1->param_start))
{
delete i;
return IMG_OVERLAP_PARAM;
}
if (s1->obj_count > 0xff)
{
delete i;
return IMG_OBJTAB_OVERFLOW;
}
if (s1->param_end > c->code () + 0x100)
{
delete i;
return IMG_WRONG_LOADCTL;
}
STR_BCU2Key *s2 = (STR_BCU2Key *) i->findStream (S_BCU2Key);
if (s2 && s2->keys () != 3)
{
delete i;
return IMG_INVALID_KEY;
}
img = new BCUImage;
img->code = c->code;
img->BCUType =
(b->bcutype == 0x0020 ? BCUImage::B_bcu20 : BCUImage::B_bcu21);
img->addr = (c->code[0x17] << 8) | (c->code[0x18]);
if (s2)
{
img->installkey = s2->installkey;
img->keys = s2->keys;
}
else
{
img->installkey = 0xFFFFFFFF;
img->keys.resize (3);
img->keys[0] = 0xFFFFFFFF;
img->keys[1] = 0xFFFFFFFF;
img->keys[2] = 0xFFFFFFFF;
}
const uchar zero[10] = { 0 };
EIBLoadRequest r;
/*unload */
r.obj = 1;
r.prop = 5;
r.start = 1;
r.memaddr = 0xffff;
r.req.set (zero, 10);
r.req[0] = 0x04;
r.result.resize (1);
r.result[0] = 0x00;
r.error = IMG_UNLOAD_ADDR;
img->load.add (r);
r.obj = 2;
r.error = IMG_UNLOAD_ASSOC;
img->load.add (r);
r.obj = 3;
r.error = IMG_UNLOAD_PROG;
img->load.add (r);
/* loadaddrtab */
r.req.set (zero, 10);
r.obj = 1;
r.req[0] = 0x01;
r.result[0] = 0x02;
r.error = IMG_LOAD_ADDR;
img->load.add (r);
GenAlloc (r.req, s1->addrtab_start, s1->addrtab_size, 0x31, 0x03, 1);
r.memaddr = s1->addrtab_start;
r.len = 1;
r.error = IMG_WRITE_ADDR;
img->load.add (r);
r.obj = 0xff;
r.memaddr += 3;
r.len = s1->addrtab_size - 4;
img->load.add (r);
r.obj = 1;
r.memaddr = 0xffff;
r.req[0] = 0x03;
r.req[1] = 0x02;
r.req[2] = (s1->addrtab_start >> 8) & 0xff;
r.req[3] = (s1->addrtab_start) & 0xff;
r.req[4] = c->code[0x09];
r.req.setpart (c->code.array () + 0x03, 5, 5);
r.error = IMG_SET_ADDR;
img->load.add (r);
r.req.set (zero, 10);
r.req[0] = 0x02;
r.result[0] = 0x01;
r.error = IMG_FINISH_ADDR;
img->load.add (r);
/* loadassoctab */
r.req.set (zero, 10);
r.obj = 2;
r.req[0] = 0x01;
r.result[0] = 0x02;
r.error = IMG_LOAD_ASSOC;
img->load.add (r);
GenAlloc (r.req, s1->assoctab_start, s1->assoctab_size, 0x31, 0x03, 1);
r.memaddr = s1->assoctab_start;
r.len = s1->assoctab_size - 1;
r.error = IMG_WRITE_ASSOC;
img->load.add (r);
r.memaddr = 0xffff;
r.req[0] = 0x03;
r.req[1] = 0x02;
r.req[2] = (s1->assoctab_start >> 8) & 0xff;
r.req[3] = (s1->assoctab_start) & 0xff;
r.req[4] = c->code[0x09];
r.req.setpart (c->code.array () + 0x03, 5, 5);
r.error = IMG_SET_ASSOC;
img->load.add (r);
r.req.set (zero, 10);
r.req[0] = 0x02;
r.result[0] = 0x01;
r.error = IMG_FINISH_ASSOC;
img->load.add (r);
/* loadproctab */
r.req.set (zero, 10);
r.obj = 3;
r.req[0] = 0x01;
r.result[0] = 0x02;
r.error = IMG_LOAD_PROG;
img->load.add (r);
GenAlloc (r.req, 0x00C8, 0x0018, 0x32, 0x01, 0);
r.error = IMG_ALLOC_LORAM;
img->load.add (r);
GenAlloc (r.req, 0x0972, 0x004A, 0x32, 0x02, 0);
r.error = IMG_ALLOC_HIRAM;
img->load.add (r);
GenAlloc (r.req, 0x0100, 0x0016, 0x32, 0x03, 0);
r.error = IMG_ALLOC_INIT;
r.len = 0x001;
r.memaddr = 0x100;
img->load.add (r);
r.obj = 0xff;
r.memaddr = 0x103;
r.len = 0x13;
img->load.add (r);
r.obj = 3;
GenAlloc (r.req, s1->readonly_start,
s1->readonly_end - s1->readonly_start, 0x30, 0x03, 1);
r.error = IMG_ALLOC_RO;
r.len = s1->readonly_end - s1->readonly_start - 1;
r.memaddr = s1->readonly_start;
if (r.len)
img->load.add (r);
GenAlloc (r.req, s1->eeprom_start, s1->eeprom_end - s1->eeprom_start,
0x31, 0x03, 0);
r.error = IMG_ALLOC_EEPROM;
r.len = s1->eeprom_end - s1->eeprom_start;
r.memaddr = s1->eeprom_start;
if (r.len)
img->load.add (r);
GenAlloc (r.req, s1->param_start, s1->param_end - s1->param_start, 0x32,
0x03, 1);
r.error = IMG_ALLOC_PARAM;
r.len = s1->param_end - s1->param_start;
r.memaddr = s1->param_start;
if (r.len > 1)
img->load.add (r);
r.memaddr = 0xffff;
r.req[0] = 0x03;
r.req[1] = 0x02;
r.req[2] = (s1->runaddr >> 8) & 0xff;
r.req[3] = (s1->runaddr) & 0xff;
r.req[4] = c->code[0x09];
r.req.setpart (c->code.array () + 0x03, 5, 5);
r.error = IMG_SET_PROG;
img->load.add (r);
r.req.set (zero, 10);
r.req[0] = 0x03;
r.req[1] = 0x03;
r.req[2] = (s1->initaddr >> 8) & 0xff;
r.req[3] = (s1->initaddr) & 0xff;
r.req[4] = (s1->saveaddr >> 8) & 0xff;
r.req[5] = (s1->saveaddr) & 0xff;
r.req[6] = (s1->sphandler >> 8) & 0xff;
r.req[7] = (s1->sphandler) & 0xff;
r.error = IMG_SET_TASK_PTR;
img->load.add (r);
r.req.set (zero, 10);
r.req[0] = 0x03;
r.req[1] = 0x04;
r.req[2] = (s1->obj_ptr >> 8) & 0xff;
r.req[3] = (s1->obj_ptr) & 0xff;
r.req[4] = (s1->obj_count) & 0xff;
r.error = IMG_SET_OBJ;
img->load.add (r);
r.req.set (zero, 10);
r.req[0] = 0x03;
r.req[1] = 0x05;
r.req[2] = (s1->appcallback >> 8) & 0xff;
r.req[3] = (s1->appcallback) & 0xff;
r.req[4] = (s1->groupobj_ptr >> 8) & 0xff;
r.req[5] = (s1->groupobj_ptr) & 0xff;
r.req[6] = (s1->seg0 >> 8) & 0xff;
r.req[7] = (s1->seg0) & 0xff;
r.req[8] = (s1->seg1 >> 8) & 0xff;
r.req[9] = (s1->seg1) & 0xff;
r.error = IMG_SET_TASK2;
img->load.add (r);
r.req.set (zero, 10);
r.req[0] = 0x02;
r.result[0] = 0x01;
r.error = IMG_FINISH_PROC;
img->load.add (r);
return IMG_IMAGE_LOADABLE;
}
delete i;
return IMG_UNKNOWN_BCUTYPE;
}
#define _(A) (A)
String
decodeBCULoadResult (BCU_LOAD_RESULT r)
{
switch (r)
{
case IMG_UNKNOWN_ERROR:
return _("unknown error");
break;
case IMG_UNRECOG_FORMAT:
return _("data not regcognized as image");
break;
case IMG_INVALID_FORMAT:
return _("invalid streams in the image");
break;
case IMG_NO_BCUTYPE:
return _("no bcu type specified");
break;
case IMG_UNKNOWN_BCUTYPE:
return _("don't know how to load the bcutype");
break;
case IMG_NO_CODE:
return _("no text segment found");
break;
case IMG_NO_SIZE:
return _("size information not found");
break;
case IMG_LODATA_OVERFLOW:
return _("too many data for low-ram");
break;
case IMG_HIDATA_OVERFLOW:
return _("too many data for hi-ram");
break;
case IMG_TEXT_OVERFLOW:
return _("too many data for eeprom");
break;
case IMG_IMAGE_LOADABLE:
return _("Image is loadable");
break;
case IMG_NO_ADDRESS:
return _("no address found in the image");
break;
case IMG_WRONG_SIZE:
return _("unexpected size of the text segment");
break;
case IMG_NO_DEVICE_CONNECTION:
return _("connection to the device failed");
break;
case IMG_MASK_READ_FAILED:
return _("read of mask version failed");
break;
case IMG_WRONG_MASK_VERSION:
return _("incompatible mask version");
break;
case IMG_CLEAR_ERROR:
return _("reseting of RunFlags failed");
break;
case IMG_RESET_ADDR_TAB:
return _("reseting of the address table failed");
break;
case IMG_LOAD_HEADER:
return _("loading of the header failed");
break;
case IMG_LOAD_MAIN:
return _("loading of the code in the eeprom failed");
break;
case IMG_ZERO_RAM:
return _("cleaning the ram failed");
break;
case IMG_FINALIZE_ADDR_TAB:
return _("finalizing the address table failed");
break;
case IMG_PREPARE_RUN:
return _("setting the RunFlags failed");
break;
case IMG_RESTART:
return _("restart failed");
break;
case IMG_LOADED:
return _("image successful loaded");
break;
case IMG_NO_START:
return _("no BCU2 load control information present");
break;
case IMG_WRONG_ADDRTAB:
return _("wrong start address of the address table");
break;
case IMG_ADDRTAB_OVERFLOW:
return _("address table too big");
break;
case IMG_OVERLAP_ASSOCTAB:
return _("association table overlaps with an other segment");
break;
case IMG_OVERLAP_TEXT:
return _("text segement overlaps with an other segment");
break;
case IMG_NEGATIV_TEXT_SIZE:
return _("segment end < text segment");
break;
case IMG_OVERLAP_PARAM:
return _("param segment overlaps with an other segment");
break;
case IMG_OVERLAP_EEPROM:
return _("eeprom segment overlaps with an other segment");
break;
case IMG_OBJTAB_OVERFLOW:
return _("too many objects");
break;
case IMG_WRONG_LOADCTL:
return _("param end not in the text segment");
break;
case IMG_UNLOAD_ADDR:
return _("error unloading address table");
break;
case IMG_UNLOAD_ASSOC:
return _("error unloading assocation table");
break;
case IMG_UNLOAD_PROG:
return _("error unloading user programm");
break;
case IMG_LOAD_ADDR:
return _("error start loading address table");
break;
case IMG_WRITE_ADDR:
return _("error allocation address table");
break;
case IMG_SET_ADDR:
return _("error setting address table start");
break;
case IMG_FINISH_ADDR:
return _("error finishing address table");
break;
case IMG_LOAD_ASSOC:
return _("error start loading association table");
break;
case IMG_WRITE_ASSOC:
return _("error allocation assocation table");
break;
case IMG_SET_ASSOC:
return _("error setting assocation table start");
break;
case IMG_FINISH_ASSOC:
return _("error finishing assocation table");
break;
case IMG_LOAD_PROG:
return _("error start loading programm");
break;
case IMG_ALLOC_LORAM:
return _("error allocation low ram");
break;
case IMG_ALLOC_HIRAM:
return _("error allocation high ram");
break;
case IMG_ALLOC_INIT:
return _("error allocation config section");
break;
case IMG_ALLOC_RO:
return _("error loading text segment");
break;
case IMG_ALLOC_EEPROM:
return _("error loading eeprom segment");
break;
case IMG_ALLOC_PARAM:
return _("error loading parameter segement");
break;
case IMG_SET_PROG:
return _("error setting programm entry");
break;
case IMG_SET_TASK_PTR:
return _("error setting task pointer");
break;
case IMG_SET_OBJ:
return _("error setting object pointer");
break;
case IMG_SET_TASK2:
return _("error setting group object pointer");
break;
case IMG_FINISH_PROC:
return _("error finishing application programm");
break;
case IMG_WRONG_CHECKLIM:
return _("wrong check limit");
break;
case IMG_AUTHORIZATION_FAILED:
return _("authorization failed");
break;
case IMG_INVALID_KEY:
return _("invalid key information");
break;
case IMG_KEY_WRITE:
return _("key write failed");
break;
default:
return _("errorcode not defined");
}
}
syntax highlighted by Code2HTML, v. 0.9.1