summaryrefslogtreecommitdiffstats
path: root/src/devices/pic/base/pic_protection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/pic/base/pic_protection.cpp')
-rw-r--r--src/devices/pic/base/pic_protection.cpp361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/devices/pic/base/pic_protection.cpp b/src/devices/pic/base/pic_protection.cpp
new file mode 100644
index 0000000..da77881
--- /dev/null
+++ b/src/devices/pic/base/pic_protection.cpp
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * 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 <qregexp.h>
+
+bool Pic::Protection::isNoneProtectedValueName(const QString &name) const
+{
+ if ( name=="Off" ) return true;
+ if ( _data.architecture()==Architecture::P17C ) return !isAllProtectedValueName(name);
+ return false;
+}
+
+bool Pic::Protection::isAllProtectedValueName(const QString &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;
+ QString mask = maskName(ProgramProtected, MemoryRangeType::Code);
+ if ( _config.findMask(QString("%1_%2").arg(mask).arg(0)) ) return BlockProtection;
+ if ( _config.findMask(mask) ) return BasicProtection;
+ return NoProtection;
+}
+
+QString 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";
+}
+
+QString Pic::Protection::bootSizeMaskName() const
+{
+ return (family()==CodeGuard ? "BSSIZ" : "BBSIZ");
+}
+
+QString 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 QString::null;
+}
+
+QString Pic::Protection::blockSizeMaskName(uint block) const
+{
+ if ( family()==CodeGuard ) {
+ Q_ASSERT( block==0 );
+ return "SSSIZ";
+ }
+ return blockMaskName(ProgramProtected, block);
+}
+
+QString 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 QString::null;
+ }
+ return QString("%1_%2").arg(maskName(type, MemoryRangeType::Code)).arg(block);
+}
+
+QString 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 QString::null;
+}
+
+bool Pic::Protection::extractRanges(const QString &name, QValueVector<Address> &starts, Address &end, bool &ok)
+{
+ ok = false;
+ QRegExp 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;
+ QString 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 QString &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;
+ QValueVector<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 QString &mask, const QString &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++) {
+ QString 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 QString &mask, const QString &name, bool &ok) const
+{
+ Q_ASSERT( family()!=CodeGuard );
+ //qDebug("extract range %s %s", mask.latin1(), name.latin1());
+ ProtectedRange pr;
+ ok = false;
+
+ QRegExp 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++) {
+ QString 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(QString("CP_%1").arg(i))==0 ) return i;
+ return MAX_NB_BLOCKS;
+}
+
+QString Pic::Protection::bootLabel() const
+{
+ if ( family()==CodeGuard ) return i18n("Boot Segment");
+ return i18n("Boot Block");
+}
+
+QString Pic::Protection::blockLabel(uint i) const
+{
+ if ( family()==CodeGuard ) {
+ if ( i==0 ) return i18n("Secure Segment");
+ return i18n("General Segment");
+ }
+ return i18n("Block #%1").arg(i);
+}