diff --git a/.cproject b/.cproject
index 21bbd2f..cf723be 100644
--- a/.cproject
+++ b/.cproject
@@ -94,9 +94,6 @@
-
-
-
@@ -145,6 +142,7 @@
@@ -232,4 +230,5 @@
+
diff --git a/Inc/flash.h b/Inc/flash.h
index f70bd32..f5d4d87 100644
--- a/Inc/flash.h
+++ b/Inc/flash.h
@@ -7,9 +7,19 @@
#define FLASH_KEYR1 0x45670123
#define FLASH_KEYR2 0xCDEF89AB
+#define FLASH_OPTKEYR1 0x08192A3B
+#define FLASH_OPTKEYR2 0x4C5D6E7F
+
#define FLASH_BANK1 0
#define FLASH_BANK2 1
+#define RDP2 0xcc
+
+#define FLASH_IS_RDP2() ((FLASH->OPTR & 0xff) == RDP2)
+#define FLASH_SET_RDP2() FLASH->OPTR |= RDP2
+#define FLASH_WP(reg, start, end) reg = (0xFF00FF00 | end << 16 | start)
+
+
/**
* Unlocks the flash, allowing writing.
*/
@@ -31,4 +41,15 @@ int flash_copy(uint32_t* src, __IO uint32_t* dst, uint32_t size);
*/
int flash_lock();
+/**
+ * Unlock the option bytes
+ */
+int flash_optunlock();
+
+/**
+ * Write and reload the option bytes
+ */
+void flash_optprogram();
+
+
#endif /* FLASH_H_ */
diff --git a/Inc/main.h b/Inc/main.h
index 7ab06fc..908ebf2 100644
--- a/Inc/main.h
+++ b/Inc/main.h
@@ -8,9 +8,12 @@
// The constants below define the memory layout documented in the README.md file
#define BOOTLOADER_SIZE 0x2000
+#define BOOTLOADER_FIRST_PAGE 0
+#define BOOTLOADER_LAST_PAGE ((BOOTLOADER_SIZE / FLASH_PAGE_SIZE) - 1)
+
#define FIRMWARE_SIZE ((FLASH_BANK_SIZE - BOOTLOADER_SIZE) / 2)
#define FIRMWARE_HEADER_SIZE 0x200
-#define FIRMWARE_FIRST_PAGE (BOOTLOADER_SIZE / FLASH_PAGE_SIZE)
+#define FIRMWARE_FIRST_PAGE (BOOTLOADER_LAST_PAGE + 1)
#define FIRMWARE_PAGE_COUNT (FIRMWARE_SIZE / FLASH_PAGE_SIZE)
#define FIRMWARE_START (FLASH_START_BANK1 + BOOTLOADER_SIZE)
@@ -21,6 +24,8 @@
#define RECOVERY_FW_START (FIRMWARE_START + FIRMWARE_SIZE)
#define RECOVERY_FW_FIRST_PAGE (FIRMWARE_FIRST_PAGE + FIRMWARE_PAGE_COUNT)
+#define RECOVERY_FW_LAST_PAGE (RECOVERY_FW_FIRST_PAGE + FIRMWARE_PAGE_COUNT - 1)
+
#define SIGNATURE_HEADER_OFFSET 8
#define SIGNATURE_LENGTH 64
@@ -28,6 +33,10 @@
#define SIGNATURE_COUNT 1
+/**
+ * Checks if the bootloader and recovery are write protected, if not protect them. Also enables the Read Protection level 2. Since this is irreversible, the code is disabled during development
+ */
+void protect_flash();
/**
* Checks the firmware a the given address. It checks the magic number, validates the size and checks the signature(s).
diff --git a/Src/flash.c b/Src/flash.c
index 568445c..d76a76d 100644
--- a/Src/flash.c
+++ b/Src/flash.c
@@ -18,6 +18,15 @@ int flash_unlock() {
return READ_BIT(FLASH->CR, FLASH_CR_LOCK);
}
+int flash_optunlock() {
+ flash_unlock();
+
+ FLASH->OPTKEYR = FLASH_OPTKEYR1;
+ FLASH->OPTKEYR = FLASH_OPTKEYR2;
+
+ return READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK);
+}
+
int _flash_erase_page(uint8_t bank, uint8_t pg) {
if(bank == FLASH_BANK1) {
CLEAR_BIT(FLASH->CR, FLASH_CR_BKER);
@@ -77,3 +86,9 @@ int flash_lock() {
SET_BIT(FLASH->CR, FLASH_CR_LOCK);
return 0;
}
+
+void flash_optprogram() {
+ SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
+ _flash_wait();
+ SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
+}
diff --git a/Src/main.c b/Src/main.c
index c8c68d2..ecc66d9 100644
--- a/Src/main.c
+++ b/Src/main.c
@@ -6,6 +6,8 @@
uint8_t fw_public_key[] = { 0xfe, 0xcb, 0x28, 0xb9, 0x50, 0xdd, 0x8b, 0x2f, 0xc7, 0x34, 0xd3, 0x60, 0x5b, 0x1a, 0xc6, 0xed, 0x02, 0x50, 0xf2, 0x4a, 0xc4, 0x75, 0xd1, 0x28, 0x7f, 0x7c, 0xb5, 0xce, 0x61, 0xd6, 0x95, 0xb9, 0xb5, 0x27, 0x0b, 0x52, 0x77, 0x42, 0x4b, 0xf3, 0xb4, 0x3c, 0xef, 0xcb, 0x56, 0xd1, 0x98, 0x22, 0x11, 0xc2, 0xe5, 0xd3, 0xf0, 0x22, 0x87, 0xb9, 0xe8, 0x20, 0xdc, 0xee, 0x9f, 0xc2, 0xad, 0x22, };
int main(void) {
+ protect_flash();
+
if (!check_firmware(UPGRADE_FW_START)) {
upgrade_firmware();
} else if (check_firmware(FIRMWARE_START)) {
@@ -43,6 +45,23 @@ int check_firmware(uintptr_t addr) {
return 0;
}
+void protect_flash() {
+#ifdef BOOTLOADER_RELEASE
+ if (FLASH_IS_RDP2()) {
+ return;
+ }
+
+ flash_optunlock();
+
+ FLASH_SET_RDP2();
+ FLASH_WP(FLASH->WRP1AR, BOOTLOADER_FIRST_PAGE, BOOTLOADER_LAST_PAGE);
+ FLASH_WP(FLASH->WRP1BR, RECOVERY_FW_FIRST_PAGE, RECOVERY_FW_LAST_PAGE);
+
+ // This resets the MCU
+ flash_optprogram();
+#endif
+}
+
void _load_firmware(uintptr_t newfw, uint8_t newfw_bank, uint8_t newfw_page, uint8_t remove_newfw) {
flash_unlock();