/********************************************************** * Performs the Debug Unlock sequence to erase all * device contents and obtain debug access. * In case the device is not locked, it will initiate * the AAP window extension sequence in order to * access the AAP before trying to unlock. **********************************************************/ void unlockTarget(void) { /* If target is unlocked we reset target and send the * AAP Window Expansion Sequence to have longer time * to access the AAP registers */ if ( !targetLocked ) { printf("Target is not locked.\n" "Performing AAP Window Expansion Sequence.\n"); performAapExpansion(); } printf("Sending Unlock Sequence\n"); /* Start a Device Erase (Debug Unlock) operation */ writeAP(AAP_CMDKEY, AAP_UNLOCK_KEY); writeAP(AAP_CMD, AAP_CMD_DEVICEERASE); writeAP(AAP_CMDKEY, 0); /* Wait long enough for Device Erase to complete. * This is typically around 50ms. We wait much longer * just to be sure. */ delayMs(1000); /* Reset and verify that target is unlocked */ hardResetTarget(); delayMs(100); /* Verify that target is unlocked. This function will raise * an exception if target is not unlocked. */ verifyUnlockedStatus(); /* If we get here, the target is unlocked */ printf("Target successfully unlocked\n"); }
/********************************************************** * Writes a value to a CPU register in the target. * * @param reg * The register number to write to * * @param value * The value to write to the register **********************************************************/ void writeCpuReg(int reg, uint32_t value) { /* Wait until debug register is ready to accept new data */ waitForRegReady(); /* Write value to Data Register */ writeAP(AP_TAR, (uint32_t)&(CoreDebug->DCRDR)); writeAP(AP_DRW, value); /* Write register number ot Selector Register. * This will update the CPU register */ writeAP(AP_TAR, (uint32_t)&(CoreDebug->DCRSR)); writeAP(AP_DRW, 0x10000 | reg); }
/********************************************************** * Verifies the current firmware against the locally * stored original. This function assumes the firmware * has been written to target starting at address 0x00. * * @param fwImage * Pointer to locally stored copy of firmware image * * @param size * Size (in bytes) of firmware image * * @returns * True if target firmware matches local copy. * False otherwise. **********************************************************/ bool verifyFirmware(uint32_t *fwImage, uint32_t size) { int i; int numWords = size / 4; bool ret = true; uint32_t value; uint32_t addr; uint32_t tarWrap = getTarWrap(); printf("Verifying firmware\n"); /* Set autoincrement on TAR */ writeAP(AP_CSW, AP_CSW_DEFAULT | AP_CSW_AUTO_INCREMENT); for ( i=0; i<numWords; i++ ) { /* Get current address */ addr = i*4; /* TAR must be initialized at every TAR wrap boundary * because the autoincrement wraps around at these */ if ( (addr & tarWrap) == 0 ) { writeAP(AP_TAR, addr); /* Do one dummy read. Subsequent reads will return the * correct result. */ readAP(AP_DRW, &value); } /* Read the value from addr */ readAP(AP_DRW, &value); /* Verify that the read value matches what is expected */ if ( value != fwImage[i] ) { printf("Verification failed at address 0x%.8x\n", addr); printf("Value is 0x%.8x, should have been 0x%.8x\n", value, fwImage[i]); ret = false; break; } } /* Disable autoincrement on TAR */ writeAP(AP_CSW, AP_CSW_DEFAULT); return ret; }
/********************************************************** * Reads one word from internal memory * * @param addr * The address to read from * * @returns * The value at @param addr **********************************************************/ uint32_t readMem(uint32_t addr) { uint32_t ret; writeAP(AP_TAR, addr); readAP(AP_DRW, &ret); readDP(DP_RDBUFF, &ret); return ret; }
/********************************************************** * Uploads and runs the flashloader on the target * The flashloader is written directly to the start * of RAM. Then the PC and SP are loaded from the * flashloader image. **********************************************************/ void uploadFlashloader(uint32_t *flImage, uint32_t size) { int w; uint32_t addr; uint32_t tarWrap; uint32_t numWords = size / 4; if ( numWords * 4 < size ) numWords++; resetAndHaltTarget(); /* Get the TAR wrap-around period */ tarWrap = getTarWrap(); printf("Uploading flashloader\n"); /* Enable autoincrement on TAR */ writeAP(AP_CSW, AP_CSW_DEFAULT | AP_CSW_AUTO_INCREMENT); for ( w=0; w<numWords; w++ ) { /* Get address of current word */ addr = RAM_START + w * 4; /* At the TAR wrap boundary we need to reinitialize TAR * since the autoincrement wraps at these */ if ( (addr & tarWrap) == 0 ) { writeAP(AP_TAR, addr); } writeAP(AP_DRW, flImage[w]); } writeAP(AP_CSW, AP_CSW_DEFAULT); printf("Booting flashloader\n"); /* Load SP (Reg 13) from flashloader image */ writeCpuReg(13, flImage[0]); /* Load PC (Reg 15) from flashloader image */ writeCpuReg(15, flImage[1]); runTarget(); }
/********************************************************** * Halts the target CPU **********************************************************/ void haltTarget(void) { int timeout = DEBUG_EVENT_TIMEOUT; writeAP(AP_TAR, (uint32_t)&(CoreDebug->DHCSR)); writeAP(AP_DRW, STOP_CMD); uint32_t dhcrState; do { writeAP(AP_TAR, (uint32_t)&(CoreDebug->DHCSR)); readAP(AP_DRW, &dhcrState); readDP(DP_RDBUFF, &dhcrState); timeout--; } while ( !(dhcrState & CoreDebug_DHCSR_S_HALT_Msk) && timeout > 0 ); if ( !(dhcrState & CoreDebug_DHCSR_S_HALT_Msk) ) { RAISE(SWD_ERROR_TIMEOUT_HALT); } }
/********************************************************** * Resets the target CPU by using the AIRCR register. * The target will be halted immediately when coming * out of reset. Does not reset the debug interface. **********************************************************/ void resetAndHaltTarget(void) { uint32_t dhcsr; int timeout = DEBUG_EVENT_TIMEOUT; /* Halt target first. This is necessary before setting * the VECTRESET bit */ haltTarget(); /* Set halt-on-reset bit */ writeMem((uint32_t)&(CoreDebug->DEMCR), CoreDebug_DEMCR_VC_CORERESET_Msk); /* Clear exception state and reset target */ writeAP(AP_TAR, (uint32_t)&(SCB->AIRCR)); writeAP(AP_DRW, (0x05FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_VECTCLRACTIVE_Msk | SCB_AIRCR_VECTRESET_Msk); /* Wait for target to reset */ do { delayUs(10); timeout--; dhcsr = readMem((uint32_t)&(CoreDebug->DHCSR)); } while ( dhcsr & CoreDebug_DHCSR_S_RESET_ST_Msk ); /* Check if we timed out */ dhcsr = readMem((uint32_t)&(CoreDebug->DHCSR)); if ( dhcsr & CoreDebug_DHCSR_S_RESET_ST_Msk ) { RAISE(SWD_ERROR_TIMEOUT_WAITING_RESET); } /* Verify that target is halted */ if ( !(dhcsr & CoreDebug_DHCSR_S_HALT_Msk) ) { RAISE(SWD_ERROR_TARGET_NOT_HALTED); } }
/********************************************************** * Writes a chunk of data to a buffer in the flashloader. * This function does not make any checks or assumptions. * It simply copies a number of words from the * local to the remote buffer. * * @param remoteAddr * Address of the flashloader buffer at the target * * @param localBuffer * The local buffer to write from * * @param numWords * Number of words to write to buffer **********************************************************/ void writeToFlashloaderBuffer(uint32_t remoteAddr, uint32_t *localBuffer, int numWords) { uint32_t bufferPointer = (uint32_t)remoteAddr; int curWord = 0; uint32_t tarWrap; /* Get the TAR wrap-around period */ tarWrap = getTarWrap(); /* Set auto increment on TAR to allow faster writes */ writeAP(AP_CSW, AP_CSW_DEFAULT | AP_CSW_AUTO_INCREMENT); /* Initialize TAR with the start of buffer */ writeAP(AP_TAR, bufferPointer); /* Send up to one full buffer of data */ while ( curWord < numWords ) { /* At TAR wrap boundary we need to reinitialize TAR * since the autoincrement wraps at these */ if ( (bufferPointer & tarWrap) == 0 ) { writeAP(AP_TAR, bufferPointer); } /* Write one word */ writeAP(AP_DRW, localBuffer[curWord]); /* Increment local and remote pointers */ bufferPointer += 4; curWord += 1; } /* Disable auto increment on TAR */ writeAP(AP_CSW, AP_CSW_DEFAULT); }
/********************************************************** * Lets the target CPU run freely (stops halting) **********************************************************/ void runTarget(void) { writeAP(AP_TAR, (uint32_t)&(CoreDebug->DHCSR)); writeAP(AP_DRW, RUN_CMD); }
/********************************************************** * Writes one word to internal memory * * @param addr * The address to write to * * @param data * The value to write * * @returns * The value at @param addr **********************************************************/ void writeMem(uint32_t addr, uint32_t data) { writeAP(AP_TAR, addr); writeAP(AP_DRW, data); }
/********************************************************** * Single steps the target **********************************************************/ void stepTarget(void) { writeAP(AP_TAR, (uint32_t)&(CoreDebug->DHCSR)); writeAP(AP_DRW, STEP_CMD); }