From 372606177357a815dd7c484739649b50118ad42e Mon Sep 17 00:00:00 2001 From: Richard Meadows Date: Sun, 18 Jan 2015 20:46:26 +0000 Subject: [PATCH] Support for the NVMCTRL Security Bit (PROT=1) --- src/cortexm.c | 5 +-- src/include/cortexm.h | 1 + src/samd20.c | 77 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/cortexm.c b/src/cortexm.c index b7f71eb..364e276 100644 --- a/src/cortexm.c +++ b/src/cortexm.c @@ -60,8 +60,6 @@ const struct command_s cortexm_cmd_list[] = { #define SIGTRAP 5 #define SIGSEGV 11 -static bool cortexm_attach(struct target_s *target); - static int cortexm_regs_read(struct target_s *target, void *data); static int cortexm_regs_write(struct target_s *target, const void *data); static int cortexm_pc_write(struct target_s *target, const uint32_t val); @@ -269,8 +267,7 @@ cortexm_probe(struct target_s *target) return true; } -static bool -cortexm_attach(struct target_s *target) +bool cortexm_attach(struct target_s *target) { ADIv5_AP_t *ap = adiv5_target_ap(target); struct cortexm_priv *priv = ap->priv; diff --git a/src/include/cortexm.h b/src/include/cortexm.h index f6170b0..f1fc07a 100644 --- a/src/include/cortexm.h +++ b/src/include/cortexm.h @@ -123,6 +123,7 @@ #define CORTEXM_DWT_FUNC_FUNC_WRITE (6 << 0) #define CORTEXM_DWT_FUNC_FUNC_ACCESS (7 << 0) +bool cortexm_attach(struct target_s *target); void cortexm_detach(struct target_s *target); void cortexm_halt_resume(struct target_s *target, bool step); diff --git a/src/samd20.c b/src/samd20.c index 64233bc..08fe6c2 100644 --- a/src/samd20.c +++ b/src/samd20.c @@ -25,9 +25,6 @@ * http://www.atmel.com/Images/Atmel-42129-SAM-D20_Datasheet.pdf * particularly Sections 12. DSU and 20. NVMCTRL */ -/* TODO: Support for the NVMCTRL Security Bit. If this is set then the - * device will probably not even be detected. - */ #include #include @@ -51,6 +48,7 @@ static bool samd20_cmd_unlock_flash(target *t); static bool samd20_cmd_read_userrow(target *t); static bool samd20_cmd_serial(target *t); static bool samd20_cmd_mbist(target *t); +static bool samd20_cmd_ssb(target *t); const struct command_s samd20_cmd_list[] = { {"erase_mass", (cmd_handler)samd20_cmd_erase_all, "Erase entire flash memory"}, @@ -59,6 +57,7 @@ const struct command_s samd20_cmd_list[] = { {"user_row", (cmd_handler)samd20_cmd_read_userrow, "Prints user row from flash"}, {"serial", (cmd_handler)samd20_cmd_serial, "Prints serial number"}, {"mbist", (cmd_handler)samd20_cmd_mbist, "Runs the built-in memory test"}, + {"set_security_bit", (cmd_handler)samd20_cmd_ssb, "Sets the Security Bit"}, {NULL, NULL, NULL} }; @@ -102,6 +101,8 @@ static const char samd20_xml_memory_map[] = "" #define SAMD20_CTRLA_CMD_LOCK 0x0040 #define SAMD20_CTRLA_CMD_UNLOCK 0x0041 #define SAMD20_CTRLA_CMD_PAGEBUFFERCLEAR 0x0044 +#define SAMD20_CTRLA_CMD_SSB 0x0045 +#define SAMD20_CTRLA_CMD_INVALL 0x0046 /* Interrupt Flag Register (INTFLAG) */ #define SAMD20_NVMC_READY (1 << 0) @@ -137,6 +138,7 @@ static const char samd20_xml_memory_map[] = "" #define SAMD20_STATUSA_BERR (1 << 10) #define SAMD20_STATUSA_CRSTEXT (1 << 9) #define SAMD20_STATUSA_DONE (1 << 8) +#define SAMD20_STATUSB_PROT (1 << 16) /* Device Identification Register (DID) */ #define SAMD20_DID_MASK 0xFFBF0000 @@ -284,8 +286,32 @@ samd20_revB_halt_resume(struct target_s *target, bool step) } } +/** + * Overload the default cortexm attach for when the samd20 is protected. + * + * If the samd20 is protected then the default cortexm attach will + * fail as the S_HALT bit in the DHCSR will never go high. This + * function allows users to attach on a temporary basis so they can + * rescue the device. + */ +static bool +samd20_protected_attach(struct target_s *target) +{ + /** + * TODO: Notify the user that we're not really attached and + * they should issue the 'monitor erase_mass' command to + * regain access to the chip. + */ -char variant_string[30]; + /* Patch back in the normal cortexm attach for next time */ + target->attach = cortexm_attach; + + /* Allow attach this time */ + return true; +} + + +char variant_string[40]; bool samd20_probe(struct target_s *target) { ADIv5_AP_t *ap = adiv5_target_ap(target); @@ -306,6 +332,7 @@ bool samd20_probe(struct target_s *target) & SAMD20_DID_DEVSEL_MASK; uint8_t revision = (did >> SAMD20_DID_REVISION_POS) & SAMD20_DID_REVISION_MASK; + uint32_t ctrlstat = adiv5_ap_mem_read(ap, SAMD20_DSU_CTRLSTAT); /* Pin Variant */ char pin_variant; @@ -322,9 +349,17 @@ bool samd20_probe(struct target_s *target) /* Revision */ char revision_variant = 'A' + revision; + /* Protected? */ + int protected = (ctrlstat & SAMD20_STATUSB_PROT); + /* Part String */ - sprintf(variant_string, "Atmel SAMD20%c%dA (rev %c)", - pin_variant, mem_variant, revision_variant); + if (protected) { + sprintf(variant_string, "Atmel SAMD20%c%dA (rev %c) (PROT=1)", + pin_variant, mem_variant, revision_variant); + } else { + sprintf(variant_string, "Atmel SAMD20%c%dA (rev %c)", + pin_variant, mem_variant, revision_variant); + } /* Setup Target */ target->driver = variant_string; @@ -339,6 +374,16 @@ bool samd20_probe(struct target_s *target) target->detach = samd20_revB_detach; target->halt_resume = samd20_revB_halt_resume; } + if (protected) { + /** + * Overload the default cortexm attach + * for when the samd20 is protected. + * This function allows users to + * attach on a temporary basis so they + * can rescue the device. + */ + target->attach = samd20_protected_attach; + } target->xml_mem_map = samd20_xml_memory_map; target->flash_erase = samd20_flash_erase; @@ -669,3 +714,23 @@ static bool samd20_cmd_mbist(target *t) return true; } +/** + * Sets the security bit + */ +static bool samd20_cmd_ssb(target *t) +{ + ADIv5_AP_t *ap = adiv5_target_ap(t); + + /* Issue the ssb command */ + adiv5_ap_mem_write(ap, SAMD20_NVMC_CTRLA, SAMD20_CTRLA_CMD_KEY | SAMD20_CTRLA_CMD_SSB); + + /* Poll for NVM Ready */ + while ((adiv5_ap_mem_read(ap, SAMD20_NVMC_INTFLAG) & SAMD20_NVMC_READY) == 0) + if(target_check_error(t)) + return -1; + + gdb_outf("Set the security bit! " + "You will need to issue 'monitor erase_mass' to clear this.\n"); + + return true; +}