Jump to content
43oh

Hard intvec rejumping through Soft intvec for Firmware updates


Recommended Posts

The idea is that any new firmware does not include the upper 512bytes of Flash,
but as IRQ vectors will change with new firmware but is now part of the firmware-block as compiler Intvec have been moved -512 bytes down.
If you put your custom Loader in the upper 512bytes too and as you never erase this block, much less chance of bricking.

 

I guess opcode for BR could change from msp family? but this does work on a G2553.
?CCS could use pragma location if it can not handle @

 

Not all vectors are available or used, so you should fill them with random value instead for the BSL password if you want some security.

But at least the BSL password will now stay the same from reversions.

static const unsigned int jumptable[49] @0xFF9E = {
  0x4210,0xFDE0,     // indirect BR &0x----
  0x4210,0xFDE2,
  0x4210,0xFDE4,
  0x4210,0xFDE6,
  0x4210,0xFDE8,
  0x4210,0xFDEA,
  0x4210,0xFDEC,
  0x4210,0xFDEE,
  0x4210,0xFDF0,
  0x4210,0xFDF2,
  0x4210,0xFDF4,
  0x4210,0xFDF6,
  0x4210,0xFDF8,
  0x4210,0xFDFA,
  0x4210,0xFDFC,
  0x4210,0xFDFE,
  0x0000,            // BSL signature
  0xFF9E,0xFFA2,     // real intvec
  0xFFA6,0xFFAA,
  0xFFAE,0xFFB2,
  0xFFB6,0xFFBA,
  0xFFBE,0xFFC2,
  0xFFC6,0xFFCA,
  0xFFCE,0xFFD2,
  0xFFD6,0xFFDA 
};
int main( void )
{ 
  WDTCTL = WDTPW + WDTHOLD;    // Stop watchdog timer
  if (jumptable[0] == 0xffff) {while(1){};}; // need to use array for something

Override default location of linker file and make a copy of it and move it to local project folder and edit:

// ------------------------------------- 
// Signature memory and interrupt vectors 
// 
 
-Z(CONST)SIGNATURE=FFDE-FFDF  // used by BSL  
-Z(CODE)INTVEC=FDE0-FDFF      // normally FFE0-FFFF 
-Z(CODE)RESET=FDFE-FDFF       // normally FFFE-FFFF

Link to post
Share on other sites
  • 2 weeks later...

#include "msp430.h"
#define UART_RX  BIT1
#define UART_TX  BIT2
#define UART_PORT(x)  (P1 ##x) 
#define softintvec    0xC0004210 // start of flash + opcode for BR

void bootloader_reset(void);
void TXdata(char* pnt, int len);
void bootloader_USCIAB0TX(void);
void bootloader_flasherase(void);
__interrupt void bootloaderRX_ISR(void);

//-------------------- define structures --------------------
struct jumpstruct {
 const unsigned long branch[16];
 const unsigned int bsl; 
 const unsigned long* vector[16]; 
};

//-------------------- declare strings ----------------------
#pragma location = "BOOTSTRINGS"
const char uartstring1[] = "run main, password anytime erases\r\n";
#pragma location = "BOOTSTRINGS"
const char uartstring2[] = "Ready for Firmware\r\n";

//-------------------- reserve a fixed ram location ---------
#pragma location = 0x200
__no_init char* passwordpnt;

//-------------------- entry on reset -----------------------
#pragma location = "BOOTLOADER"
void bootloader_reset(void)
{ 
  asm(" MOV #SFE(CSTACK), SP");         // set stack pointer
  WDTCTL = WDTPW+WDTHOLD;
 
  if (CALBC1_1MHZ != 0xff){             // erased by mistake?
    BCSCTL1 = CALBC1_1MHZ;		// Set DCO to factory calibrate 1MHz  
    DCOCTL = CALDCO_1MHZ;
  } 
  UCA0CTL1 = UCSWRST;                   // Set UCSWRST (hold USCI in Reset state)
  UCA0CTL1 |= UCSSEL_2;                 // Use SMCLK
  UCA0CTL0 = 0;                         // UART N,8,1
  UCA0BR0 = 104;		        // upper register (9600)
  UCA0BR1 = 0;                          // the lower rate register
  UCA0MCTL = UCBRS1;                    // don't use modulation as it jitters
  UART_PORT(SEL)  |= UART_TX + UART_RX;
  UART_PORT(SEL2) |= UART_TX + UART_RX;
  UCA0CTL1 &= ~UCSWRST;                 // relase reset, Initialize USCI state machine  
  IE2 |= UCA0RXIE;                      // enable USCI_A0 RX interrupt
  
  if (*(int*)0xC01E != 0xffff){         // is reset vector filled in?
    TXdata((char*)&uartstring1, sizeof(uartstring1)-1);
    passwordpnt = (char*) &uartstring1; // use string1 as password
    __bis_SR_register(GIE);             // so our RX_ISR can get data
    asm (" BR &0xC01E");                // indirect jump 
  }     
  TXdata((char*)&uartstring2, sizeof(uartstring2)-1);
  BCSCTL3 |= LFXT1S_2;                  // aclk = vloclk
  BCSCTL1 |= DIVA_3;                    // aclk divided by 8
  WDTCTL = WDTPW+WDTCNTCL+WDTSSEL;      // aclk sourced ~28sec
  __bis_SR_register(LPM3_bits);         // trap it
}

//-------------------- uart byte tx routine -----------------
#pragma location = "BOOTLOADER"
void TXdata(char* pnt, int len)
{
  while(len--){
    UCA0TXBUF = *pnt++;
    while (!(IFG2 & UCA0TXIFG)); 
  }
} 

//-------------------- UartRX sniffer ISR -------------------
#pragma location = "BOOTLOADER"
__interrupt void bootloaderRX_ISR(void){
  if (IFG2 & UCA0RXIFG){                        // our USCI_A0 Recive Interrupt?
    if (UCA0RXBUF == *passwordpnt){             // a match?
      if (++passwordpnt == uartstring1+sizeof(uartstring1)-3){
        bootloader_flasherase();
        WDTCTL = WDTPW+WDTCNTCL+WDTSSEL;        // reset the system
        __bis_SR_register_on_exit(LPM3_bits);
      }  
    }
    else passwordpnt = (char*) &uartstring1;    // reset it to the start  
    if (*(int*)0xC00E != 0xffff){               // is USCIAB0RX vector filled in?
      IFG2 |= UCA0RXIFG;                        // if real routine needs it
      asm (" BR &0xC00E");                      // indirect jump to user isr
    }
  } 
}

//-------------------- flash erase blocks -------------------
#pragma location = "BOOTLOADER"
void bootloader_flasherase(void){
  int* pnt = (int*) 0xC000;                     // start of flash
  unsigned int i = 16*2-1;                      // erase 16K -512B
  WDTCTL = WDTPW+WDTHOLD;                       // no WDT
  __bic_SR_register(GIE);                       // so no interupt 
  FCTL2 = FWKEY + FSSEL0 + FN1;                 // MCLK/3 for Flash Timing Generator
  FCTL3 = FWKEY;                                // Clear Lock bit
  while (i--){
    FCTL1 = FWKEY + ERASE;                      // Set Erase bit
    *pnt = 0;                                   // Dummy write to erase Flash block
    pnt += 256;                                 // 256 ints up (e.g 512 bytes)
  } 
  FCTL3 = FWKEY + LOCK;                         // Set LOCK bit
}

//-------------------- const rejumping real intvec ----------
#pragma location = "JUMPTABLE"
const struct jumpstruct jumptable = {
  .branch[0]  = softintvec +  0 * 0x20000u,
  .branch[1]  = softintvec +  1 * 0x20000u,
  .branch[2]  = softintvec +  2 * 0x20000u,
  .branch[3]  = softintvec +  3 * 0x20000u,
  .branch[4]  = softintvec +  4 * 0x20000u,
  .branch[5]  = softintvec +  5 * 0x20000u,
  .branch[6]  = softintvec +  6 * 0x20000u,
  .branch[7]  = softintvec +  7 * 0x20000u,
  .branch[8]  = softintvec +  8 * 0x20000u,
  .branch[9]  = softintvec +  9 * 0x20000u,
  .branch[10] = softintvec + 10 * 0x20000u,
  .branch[11] = softintvec + 10 * 0x20000u,
  .branch[12] = softintvec + 12 * 0x20000u,
  .branch[13] = softintvec + 13 * 0x20000u,
  .branch[14] = softintvec + 14 * 0x20000u,
  .branch[15] = softintvec + 15 * 0x20000u,
  .bsl = 0x0000,
  .vector[0]  = &jumptable.branch[0],
  .vector[1]  = &jumptable.branch[1],
  .vector[2]  = &jumptable.branch[2],
  .vector[3]  = &jumptable.branch[3],
  .vector[4]  = &jumptable.branch[4],
  .vector[5]  = &jumptable.branch[5],
  .vector[6]  = &jumptable.branch[6],
  .vector[7]  = (unsigned long*) &bootloaderRX_ISR,
  .vector[8]  = &jumptable.branch[8],
  .vector[9]  = &jumptable.branch[9],
  .vector[10] = &jumptable.branch[10],
  .vector[11] = &jumptable.branch[11],
  .vector[12] = &jumptable.branch[12],
  .vector[13] = &jumptable.branch[13],
  .vector[14] = &jumptable.branch[14],
  .vector[15] = (unsigned long*) &bootloader_reset
};    
#pragma required=jumptable      // tell compiler it's not a dead var
Override linker location, copy it and edit the last sections so it looks like this

it moves intvec to just before code so firmware is just now one block including the vectors

-Z(CONST)DATA16_C,DATA16_ID,TLS16_ID,DIFUNCT,CHECKSUM=C020-FDFF // normally C000-FFDD

// -------------------------------------
// Code
//

-Z(CODE)CSTART,ISR_CODE,CODE_ID=C020-FDFF	// normally C000-FFDD
-P(CODE)CODE=C020-FDFF				// normally C000-FFDD

// -------------------------------------
// Signature memory and interrupt vectors
//

-Z(CONST)SIGNATURE=FFDE-FFDF
-Z(CODE)INTVEC=C000-C01F		// normally FFE0-FFFF
-Z(CODE)RESET=C01E-C01F			// normally FFFE-FFFF
-Z(CODE)BOOTLOADER=FE00-FF5F		// new addition
-Z(CONST)BOOTSTRINGS=FF60-FF9D		// new addition
-Z(CONST)JUMPTABLE=FF9E-FFFF		// new addition

?Done with  IAR Workbench for G2553

The bootloaders Uart RX routine sniffs all incoming data so user can share uart for its intended purpose,

 

so if you have a Cellular GSM module and you want remote firmware update capability

?this may be best near un-brickable way, as soon it detects the password it erase the Flash (except the boot loader block)

and now it will go in to a waiting sequence for new firmware, It will send a text string ~28second to remind you.

?The firmware Flash Loader itself is not done yet, probably need to move up to a 1K size block to fit everything

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...