You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/devices/pic/base/pic_protection.cpp

362 lines
11 KiB

/***************************************************************************
* Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> *
* *
* 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. *
***************************************************************************/
#include "pic_protection.h"
#include "pic_config.h"
#include <tqregexp.h>
bool Pic::Protection::isNoneProtectedValueName(const TQString &name) const
{
if ( name=="Off" ) return true;
if ( _data.architecture()==Architecture::P17C ) return !isAllProtectedValueName(name);
return false;
}
bool Pic::Protection::isAllProtectedValueName(const TQString &name) const
{
if ( name=="All" ) return true;
if ( _data.architecture()==Architecture::P17C ) return ( name=="Code-protected microcontroller" );
return false;
}
Pic::Protection::Family Pic::Protection::family() const
{
if ( _config.findMask("WRTBS") ) return CodeGuard;
TQString mask = maskName(ProgramProtected, MemoryRangeType::Code);
if ( _config.findMask(TQString("%1_%2").tqarg(mask).tqarg(0)) ) return BlockProtection;
if ( _config.findMask(mask) ) return BasicProtection;
return NoProtection;
}
TQString Pic::Protection::securityValueName(Type type) const
{
if ( type==StandardSecurity ) return "Standard Security";
if ( type==HighSecurity ) return "High Security";
Q_ASSERT( type==Nb_Types );
return "Off";
}
TQString Pic::Protection::bootSizeMaskName() const
{
return (family()==CodeGuard ? "BSSIZ" : "BBSIZ");
}
TQString Pic::Protection::bootMaskName(Type type) const
{
Q_ASSERT( type!=Nb_Types );
if ( family()==CodeGuard ) {
if ( type==WriteProtected ) return "WRTBS";
if ( type==StandardSecurity || type==HighSecurity ) return "BSSEC";
} else {
if ( type==ProgramProtected ) return "CPB";
if ( type==WriteProtected ) return "WRTB";
if ( type==ReadProtected ) return "EBTRB";
}
return TQString();
}
TQString Pic::Protection::blockSizeMaskName(uint block) const
{
if ( family()==CodeGuard ) {
Q_ASSERT( block==0 );
return "SSSIZ";
}
return blockMaskName(ProgramProtected, block);
}
TQString Pic::Protection::blockMaskName(Type type, uint block) const
{
Q_ASSERT( type!=Nb_Types );
if ( family()==CodeGuard ) {
if ( type==WriteProtected ) return (block==0 ? "WRTSS" : "WRTGS");
if ( type==StandardSecurity || type==HighSecurity ) return (block==0 ? "SSSEC" : "GSSEC");
return TQString();
}
return TQString("%1_%2").tqarg(maskName(type, MemoryRangeType::Code)).tqarg(block);
}
TQString Pic::Protection::maskName(Type type, MemoryRangeType mtype) const
{
Q_ASSERT( type!=Nb_Types );
switch (mtype.type()) {
case MemoryRangeType::Code:
if ( type==ProgramProtected ) {
if ( _data.architecture()==Architecture::P17C ) return "PM";
if ( _data.architecture()==Architecture::P30F || _data.architecture()==Architecture::P24F ) return "GCP";
return "CP";
}
if ( type==WriteProtected ) {
if ( _data.architecture()==Architecture::P30F || _data.architecture()==Architecture::P24F ) return "GWRP";
return "WRT";
}
if ( type==ReadProtected ) return "EBTR";
break;
case MemoryRangeType::Eeprom:
if ( type==ProgramProtected ) return "CPD";
if ( type==WriteProtected ) return "WRTD";
break;
case MemoryRangeType::Cal:
if ( type==ProgramProtected ) return "CPC";
break;
case MemoryRangeType::Config:
if ( type==WriteProtected ) return "WRTC";
if ( type==ReadProtected ) return "EBTRC";
break;
case MemoryRangeType::Nb_Types: Q_ASSERT(false); break;
default: break;
}
return TQString();
}
bool Pic::Protection::extractRanges(const TQString &name, TQValueVector<Address> &starts, Address &end, bool &ok)
{
ok = false;
TQRegExp regexp("([A-F0-9]+)(/[A-F0-9]+)?(/[A-F0-9]+)?:([A-F0-9]+)");
if ( !regexp.exactMatch(name) ) return false;
bool ok1;
end = fromHex(regexp.cap(regexp.numCaptures()), &ok1);
if ( !ok1 ) {
qDebug("Malformed end address");
return true;
}
starts.clear();
for (int i=1; i<regexp.numCaptures(); i++) {
if ( regexp.cap(i).isEmpty() ) break;
bool ok1;
TQString s = (i==1 ? regexp.cap(i) : regexp.cap(i).mid(1));
Address start = fromHex(s, &ok1);
if ( !ok1 ) {
qDebug("Malformed start address %s", s.latin1());
return true;
}
if ( start>=end && (starts.count()==0 || starts[starts.count()-1]<start) ) {
qDebug("Start addresses should be ordered");
return true;
}
starts.append(start);
}
ok = true;
return true;
}
AddressRangeVector Pic::Protection::extractRanges(const TQString &name, MemoryRangeType type) const
{
if ( isNoneProtectedValueName(name) ) return AddressRange();
if ( isAllProtectedValueName(name) ) {
const MemoryRangeData &rdata = _data.range(type);
return AddressRange(rdata.start, rdata.end);
}
bool ok1;
TQValueVector<Address> starts;
Address end;
bool ok2 = extractRanges(name, starts, end, ok1);
Q_ASSERT(ok1);
Q_ASSERT(ok2);
Q_UNUSED(ok2);
AddressRangeVector rv;
for (uint i=0; i<uint(starts.count()); i++) rv.append(AddressRange(starts[i], end));
return rv;
}
bool Pic::Protection::checkRange(const TQString &mask, const TQString &name) const
{
if ( family()!=CodeGuard ) {
bool ok;
(void)extractRange(mask, name, ok);
return ok;
}
bool isBootBlock = false;
int block = 0;
Type ptype = Nb_Types;
for (uint i=0; i<3; i++) {
isBootBlock = ( i==0 );
block = i - 1;
for (uint k=0; k<Nb_Types; k++) {
TQString mname = (isBootBlock ? bootMaskName(Type(k)) : blockMaskName(Type(k), block));
if ( mask!=mname ) continue;
ptype = Type(k);
break;
}
if ( ptype!=Nb_Types ) break;
}
if ( ptype==Nb_Types ) {
qDebug("Unknown protected memory range");
return false;
}
// #### TODO
return true;
}
Pic::Protection::ProtectedRange Pic::Protection::extractRange(const TQString &mask, const TQString &name, bool &ok) const
{
Q_ASSERT( family()!=CodeGuard );
//qDebug("extract range %s %s", mask.latin1(), name.latin1());
ProtectedRange pr;
ok = false;
TQRegExp rexp("([A-Z]+)(?:_([0-9])|)");
if ( !rexp.exactMatch(mask) ) {
qDebug("Malformed block range");
return pr;
}
bool isBootBlock = false;
MemoryRangeType rtype = MemoryRangeType::Nb_Types;
Type ptype = Nb_Types;
for (MemoryRangeType type; type<=MemoryRangeType::Nb_Types; ++type) { // #### danger: <=
isBootBlock = ( type==MemoryRangeType::Nb_Types );
for (uint k=0; k<Nb_Types; k++) {
TQString mname = (isBootBlock ? bootMaskName(Type(k)) : maskName(Type(k), type));
if ( rexp.cap(1)!=mname ) continue;
rtype = (isBootBlock ? MemoryRangeType(MemoryRangeType::Code) : type);
ptype = Type(k);
if ( !rexp.cap(2).isEmpty() ) {
if ( isBootBlock || (rtype!=MemoryRangeType::Code && rtype!=MemoryRangeType::Eeprom) ) {
qDebug("Multiple blocks only for code and eeprom");
return pr;
}
}
break;
}
if ( rtype!=MemoryRangeType::Nb_Types ) break;
}
if ( rtype==MemoryRangeType::Nb_Types ) {
qDebug("Unknown protected memory range");
return pr;
}
if ( isNoneProtectedValueName(name) ) {
ok = true;
return pr;
}
const Config::Mask *bmask = _config.findMask(bootMaskName(ptype));
const Config::Mask *bsmask = _config.findMask(bootSizeMaskName());
const MemoryRangeData &rdata = _data.range(rtype);
if ( isAllProtectedValueName(name) ) {
if ( rtype==MemoryRangeType::Code && !isBootBlock && bmask ) {
qDebug("Protected range should be explicit with boot block");
return pr;
}
if (isBootBlock) {
if ( bsmask==0 ) {
qDebug("Protected range should be explicit when boot size not present");
return pr;
}
Address start = _data.range(MemoryRangeType::Code).start;
pr.starts.append(start);
for (uint k=0; k<uint(bsmask->values.count()); k++) {
bool ok1;
uint size = bsmask->values[k].name.toUInt(&ok1);
if ( !ok1 ) {
qDebug("Could not recognize boot size value");
return pr;
}
if ( size==0 ) {
qDebug("Boot size cannot be zero");
return pr;
}
Address end = 2 * size - 1; // instruction words
if ( pr.ends.count()!=0 && end==pr.ends[pr.ends.count()-1] ) continue;
pr.ends.append(end);
qHeapSort(pr.ends);
}
} else {
pr.starts.append(rdata.start);
pr.ends.append(rdata.end);
}
ok = true;
return pr;
}
if ( isBootBlock && bsmask ) {
qDebug("Protected range should not be explicit when boot size is present");
return pr;
}
// extract start and end
Address end;
bool ok1;
if ( !extractRanges(name, pr.starts, end, ok1) ) {
qDebug("Could not recognized explicit range");
return pr;
}
if ( !ok1 ) return pr;
if ( end>rdata.end ) {
qDebug("End is beyond memory range");
return pr;
}
if ( (rtype!=MemoryRangeType::Code || isBootBlock) && (pr.starts.count()>1 || !rexp.cap(2).isEmpty() || bmask==0) ) {
qDebug("Only code with blocks and boot can have multiple protected ranges");
return pr;
}
if ( isBootBlock && pr.starts[0]!=0 ) {
qDebug("Boot block start should be zero");
return pr;
}
pr.ends.append(end);
// check with boot block
if ( pr.starts.count()>1 ) {
if ( bmask==0 ) {
qDebug("No boot mask");
return pr;
}
for (uint i=0; i<uint(bmask->values.count()); i++) {
if ( bmask->values[i].name=="Off" ) continue;
bool ok1;
ProtectedRange bpr = extractRange(bmask->name, bmask->values[i].name, ok1);
if ( !ok1 ) return pr;
if ( bpr.ends.count()!=pr.starts.count() ) {
qDebug("Boot number of ends (%i) should be the same as code number of starts (%i)", int(bpr.ends.count()), int(pr.starts.count()));
return pr;
}
for (uint k=0; k<uint(bpr.ends.count()); k++) {
if ( bpr.ends[k]+1!=pr.starts[k] ) {
qDebug("%i: End of boot block (%s) doesn't match start of code block (%s)", k, toHexLabelAbs(bpr.ends[k]).latin1(), toHexLabelAbs(pr.starts[k]).latin1());
return pr;
}
}
}
}
ok = true;
return pr;
}
bool Pic::Protection::hasBootBlock() const
{
return ( _config.findMask("CPB") || _config.findMask(bootSizeMaskName()) );
}
uint Pic::Protection::nbBlocks() const
{
if ( family()==CodeGuard ) return 2; // codeguard : secure segment + general segment
for (uint i=0; i<MAX_NB_BLOCKS; i++)
if ( _config.findMask(TQString("CP_%1").tqarg(i))==0 ) return i;
return MAX_NB_BLOCKS;
}
TQString Pic::Protection::bootLabel() const
{
if ( family()==CodeGuard ) return i18n("Boot Segment");
return i18n("Boot Block");
}
TQString Pic::Protection::blockLabel(uint i) const
{
if ( family()==CodeGuard ) {
if ( i==0 ) return i18n("Secure Segment");
return i18n("General Segment");
}
return i18n("Block #%1").tqarg(i);
}