/***************************************************************************
* 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 ) ;
}