Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Allow for downgrading from future firmware versions with TCM enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
dc42 committed Dec 21, 2020
1 parent b8985a5 commit 3647d1b
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 14 deletions.
19 changes: 15 additions & 4 deletions cores/arduino/Flash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,17 @@ uint32_t flash_clear_gpnvm(uint32_t ul_gpnvm)
return FLASH_RC_ERROR;
}

// Read all nine GPNVM bits. Return 0xFFFFFFFF if failed, else the GPNVM bits in bits 0 to 8.
uint32_t flash_read_gpnvm_bits() noexcept
{
if (EFC_RC_OK != efc_perform_command(EFC, EFC_FCMD_GGPB, 0))
{
return 0xFFFFFFFF;
}

return efc_get_result(EFC) & ((1ul << 9) - 1ul);
}

/**
* \brief Check if the given GPNVM bit is set or not.
*
Expand Down Expand Up @@ -848,7 +859,7 @@ uint32_t flash_is_gpnvm_set(uint32_t ul_gpnvm)
*
* \return 0 if successful; otherwise returns an error code.
*/
uint32_t flash_read_unique_id(uint32_t *pul_data)
uint32_t flash_read_unique_id(uint32_t *pul_data) noexcept
{
// dc42 Bug fix: must disable interrupts while executing the EFC read command
const irqflags_t flags = cpu_irq_save();
Expand All @@ -866,7 +877,7 @@ uint32_t flash_read_unique_id(uint32_t *pul_data)
*
* \return 0 if successful; otherwise returns an error code.
*/
uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size)
uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size) noexcept
{
if (ul_size > (FLASH_USER_SIG_SIZE / sizeof(uint32_t))) {
/* Only 512 byte to store user signature */
Expand All @@ -888,7 +899,7 @@ uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size)
*
* \return 0 if successful; otherwise returns an error code.
*/
uint32_t flash_write_user_signature(const uint32_t *p_buffer)
uint32_t flash_write_user_signature(const uint32_t *p_buffer) noexcept
{
/* Write page buffer.
* Writing 8-bit and 16-bit data is not allowed and may lead to
Expand All @@ -909,7 +920,7 @@ uint32_t flash_write_user_signature(const uint32_t *p_buffer)
*
* \return 0 if successful; otherwise returns an error code.
*/
uint32_t flash_erase_user_signature(void)
uint32_t flash_erase_user_signature(void) noexcept
{
/* Perform the erase user signature command */
return efc_perform_command(EFC, EFC_FCMD_EUS, 0);
Expand Down
9 changes: 5 additions & 4 deletions cores/arduino/Flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@ uint32_t flash_is_locked(uint32_t ul_start, uint32_t ul_end);
uint32_t flash_set_gpnvm(uint32_t ul_gpnvm);
uint32_t flash_clear_gpnvm(uint32_t ul_gpnvm);
uint32_t flash_is_gpnvm_set(uint32_t ul_gpnvm);
uint32_t flash_read_unique_id(uint32_t *pul_data); // read 4 dwords of unique ID
uint32_t flash_read_gpnvm_bits() noexcept;
uint32_t flash_read_unique_id(uint32_t *pul_data) noexcept; // read 4 dwords of unique ID

#if (SAM4S || SAM4E || SAM4N || SAM4C || SAMG || SAM4CP || SAM4CM || SAMV71 || SAMV70 || SAMS70 || SAME70)
uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size);
uint32_t flash_write_user_signature(const uint32_t *p_buffer);
uint32_t flash_erase_user_signature(void);
uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size) noexcept;
uint32_t flash_write_user_signature(const uint32_t *p_buffer) noexcept;
uint32_t flash_erase_user_signature(void) noexcept;
#endif

/// @cond 0
Expand Down
41 changes: 35 additions & 6 deletions variants/same70/startup_same70.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#include "same70.h"
#include "system_same70.h"
#include "wdt/wdt.h"
#include "Flash.h"
#include "Reset.h"

#if __FPU_USED /* CMSIS defined value to indicate usage of FPU */
#include "fpu/fpu.h"
Expand Down Expand Up @@ -317,19 +319,22 @@ const DeviceVectors exception_table = {
.pfnRSWDT_Handler = (void*) RSWDT_Handler /* 63 Reinforced Secure Watchdog Timer */
};

// This must be marked noinline so that R0 is loaded with the required value for SP
__attribute((noinline)) void SetStackPointer(uint32_t *topOfStack)
{
__asm volatile("msr msp, r0");
}

/**
* \brief This is the code that gets called on processor reset.
* To initialize the device, and call the main() routine.
*/
__attribute__((noreturn)) void Reset_Handler(void)
{
// Clear the nocache RAM segment
for (uint32_t *pDest = &_szero_nocache; pDest < &_ezero_nocache;)
{
*pDest++ = 0;
}
// If TCM is allocated then SP may point beyond the end of RAM, so move it
SetStackPointer(&_ezero_nocache);

/* Initialize the relocate segment */
// Initialize the relocate segment
{
const uint32_t *pSrc = &_etext;
uint32_t *pDest = &_srelocate;
Expand All @@ -343,6 +348,30 @@ __attribute__((noreturn)) void Reset_Handler(void)
}
}

// Check that no TCM is allocated before we relocate the stack to the top of memory. This uses a RAMFUNC, so we must initialise the relocate segment before here.
// The temporary stack we are on is in the non-cached memory segment, so don't clear that segment until after we have relocated the stack.
if (flash_read_gpnvm_bits() & ((1ul << 7) | (1ul << 8)))
{
// TCM is allocated - we are probably downgrading from later firmware that uses TCM. Disable TCM and reboot.
flash_clear_gpnvm(7);
flash_clear_gpnvm(8);
// On some microchip processors, we need a delay between writing to flash and resetting
for (unsigned int i = 0; i < 10000; ++i)
{
__asm volatile("nop");
}
Reset();
}

// Now it's safe to reset the stack pointer to the top of memory
SetStackPointer(&_estack);

// Clear the nocache RAM segment
for (uint32_t *pDest = &_szero_nocache; pDest < &_ezero_nocache;)
{
*pDest++ = 0;
}

/* Clear the zero segment */
for (uint32_t *pDest = &_szero; pDest < &_ezero;)
{
Expand Down

0 comments on commit 3647d1b

Please sign in to comment.