Repository navigation
fix(stm32f4): land #166 — erase every sector in range; each region its own sectors (rebased) #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,15 +15,25 @@ | |
| /* | ||
| * STM32F407 Flash Memory Map (1MB total) | ||
| * | ||
| * 0x08000000 - 0x08003FFF (16K) Stage-0 (eBootloader) | ||
| * 0x08004000 - 0x0800FFFF (48K) Stage-1 (E-Boot) | ||
| * 0x08010000 - 0x0807FFFF (448K) Slot A (application firmware) | ||
| * 0x08080000 - 0x080EFFFF (448K) Slot B (candidate firmware) | ||
| * 0x080F0000 - 0x080F3FFF (16K) Recovery image (golden) | ||
| * 0x080F4000 - 0x080F5FFF (8K) Boot control (primary) | ||
| * 0x080F6000 - 0x080F7FFF (8K) Boot control (backup) | ||
| * 0x080F8000 - 0x080F9FFF (8K) Boot log | ||
| * 0x080FA000 - 0x080FFFFF (24K) Device config / reserved | ||
| * The F407 erases whole sectors only, and they are not uniform: | ||
| * sectors 0-3 are 16K, sector 4 is 64K, sectors 5-11 are 128K. Every | ||
| * region therefore owns whole sectors -- erasing one region (a slot | ||
| * update, a boot control save, a log clear) must never erase another. | ||
| * Slot B, the recovery image, both boot control copies and the boot log | ||
| * used to share sector 11, so saving the boot control block wiped the | ||
| * other four. | ||
| * | ||
| * Sector Address range Size Region | ||
| * 0 0x08000000 - 0x08003FFF 16K Stage-0 (eBootloader) | ||
| * 1-3 0x08004000 - 0x0800FFFF 48K Stage-1 (E-Boot) | ||
| * 4 0x08010000 - 0x0801FFFF 64K Boot log | ||
| * 5-6 0x08020000 - 0x0805FFFF 256K Slot A (application firmware) | ||
| * 7-8 0x08060000 - 0x0809FFFF 256K Slot B (candidate firmware) | ||
| * 9 0x080A0000 - 0x080BFFFF 128K Recovery image (golden) | ||
| * 10 0x080C0000 - 0x080DFFFF 128K Boot control (primary) | ||
| * 11 0x080E0000 - 0x080FFFFF 128K Boot control (backup) | ||
| * | ||
| * Stage-0 and stage-1 match stm32f4_stage0.ld and stm32f4_stage1.ld. | ||
| */ | ||
|
|
||
| #define STM32F4_FLASH_BASE 0x08000000 | ||
|
|
@@ -35,22 +45,73 @@ | |
| #define STM32F4_STAGE1_ADDR 0x08004000 | ||
| #define STM32F4_STAGE1_SIZE (48 * 1024) | ||
|
|
||
| #define STM32F4_SLOT_A_ADDR 0x08010000 | ||
| #define STM32F4_SLOT_A_SIZE (448 * 1024) | ||
| #define STM32F4_LOG_ADDR 0x08010000 | ||
| #define STM32F4_LOG_SIZE (64 * 1024) | ||
|
Comment on lines
+48
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. Factory resets can lose their log event Both factory-reset paths set log_head to zero without erasing the isolated log sector, and eos_boot_log_append() wraps its 32-entry head without erasing or rotating programmed storage. If entry zero was already written when a reset occurs, or the log fills and wraps on STM32F4, later writes can be corrupted or rejected and leave the head stuck, while pre-reset entries remain available through log collection. Agent Prompt
|
||
|
|
||
| #define STM32F4_SLOT_B_ADDR 0x08080000 | ||
| #define STM32F4_SLOT_B_SIZE (448 * 1024) | ||
| #define STM32F4_SLOT_A_ADDR 0x08020000 | ||
| #define STM32F4_SLOT_A_SIZE (256 * 1024) | ||
|
Comment on lines
+51
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. The packer example targets the boot log The usage example in tools/imgpack.py still supplies 0x08010000 as the load and entry address, although that address now belongs to the boot log rather than Slot A. A user following that example for STM32F4 can create an image with an authenticated entry outside its firmware slot, which the boot path uses as its jump address. Agent Prompt
Comment on lines
+48
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. Generated firmware targets boot log EosConfigGenerator.generate_boot_yaml() in ebuild still places STM32F4 Slot A at 0x08016000, which this change places inside eBoot’s new boot-log sector. When ebuild generates flash and linker inputs for an updated eBoot build, those inputs target the log instead of the slot eBoot scans at 0x08020000. Agent Prompt
|
||
|
|
||
| #define STM32F4_RECOVERY_ADDR 0x080F0000 | ||
| #define STM32F4_RECOVERY_SIZE (16 * 1024) | ||
| #define STM32F4_SLOT_B_ADDR 0x08060000 | ||
| #define STM32F4_SLOT_B_SIZE (256 * 1024) | ||
|
|
||
| #define STM32F4_BOOTCTL_ADDR 0x080F4000 | ||
| #define STM32F4_BOOTCTL_BACKUP_ADDR 0x080F6000 | ||
| #define STM32F4_RECOVERY_ADDR 0x080A0000 | ||
| #define STM32F4_RECOVERY_SIZE (128 * 1024) | ||
|
|
||
| #define STM32F4_LOG_ADDR 0x080F8000 | ||
| #define STM32F4_BOOTCTL_ADDR 0x080C0000 | ||
| #define STM32F4_BOOTCTL_SIZE (128 * 1024) | ||
|
|
||
| #define STM32F4_BOOTCTL_BACKUP_ADDR 0x080E0000 | ||
| #define STM32F4_BOOTCTL_BACKUP_SIZE (128 * 1024) | ||
|
Comment on lines
+60
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4. Existing devices lose boot images The new STM32F4 addresses make eBoot read boot control and scan slots at different locations from those used by ebuild’s vendored eBoot snapshot. If an ebuild-provisioned device is moved to this bootloader without a flash-layout migration, its existing control copies and firmware images remain at the old addresses and are not found. Agent Prompt
|
||
|
|
||
| #define STM32F4_VECTOR_OFFSET (STM32F4_STAGE1_ADDR - STM32F4_FLASH_BASE) | ||
|
|
||
| /* ---- Flash sector geometry ---- */ | ||
|
|
||
| #define STM32F4_FLASH_SECTORS 12 | ||
|
|
||
| /** | ||
| * @brief Sector number holding @p addr, or -1 outside the 1MB array. | ||
| */ | ||
| static inline int stm32f4_flash_sector_of(uint32_t addr) | ||
| { | ||
| if (addr < STM32F4_FLASH_BASE) | ||
| return -1; | ||
| uint32_t off = addr - STM32F4_FLASH_BASE; | ||
| if (off < 0x10000) /* sectors 0-3: 16K each */ | ||
| return (int)(off / 0x4000); | ||
| if (off < 0x20000) /* sector 4: 64K */ | ||
| return 4; | ||
| if (off < STM32F4_FLASH_SIZE) /* sectors 5-11: 128K each */ | ||
| return 4 + (int)(off / 0x20000); | ||
| return -1; | ||
| } | ||
|
|
||
| /** | ||
| * @brief First and last sector an erase of [addr, addr + len) must clear. | ||
| * | ||
| * Every sector the range touches is included. A sector is the smallest | ||
| * unit the F407 can erase, so the erase may clear bytes past either end of | ||
| * the range; the memory map above keeps each region sector-aligned so | ||
| * those bytes never belong to another region. | ||
| * | ||
| * @return 0 on success; -1 for len == 0, or a range that wraps or leaves | ||
| * the flash array (nothing is to be erased then). | ||
| */ | ||
| static inline int stm32f4_flash_sector_range(uint32_t addr, size_t len, | ||
| int *first, int *last) | ||
| { | ||
| if (len == 0 || (uint64_t)addr + len > (uint64_t)STM32F4_FLASH_BASE + | ||
| STM32F4_FLASH_SIZE) | ||
| return -1; | ||
| int f = stm32f4_flash_sector_of(addr); | ||
| int l = stm32f4_flash_sector_of((uint32_t)(addr + len - 1)); | ||
| if (f < 0 || l < 0) | ||
| return -1; | ||
| *first = f; | ||
| *last = l; | ||
| return 0; | ||
| } | ||
|
|
||
| /* UART for recovery */ | ||
| #define STM32F4_UART_INSTANCE 2 /* USART2 on PA2/PA3 */ | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: embeddedos-org/eBoot
Length of output: 37340
Script executed:
Repository: embeddedos-org/eBoot
Length of output: 43541
Script executed:
Repository: embeddedos-org/eBoot
Length of output: 8528
Web query:
STM32F407 datasheet 128 Kbyte sector erase time maximum x8 parallelism 4 secondsResult:
Feed the watchdog between sector erases.
Both factory-reset paths erase Slot A and Slot B consecutively. Each slot spans two 128 KiB sectors, so the current loop can perform four blocking erases before the recovery loop feeds the watchdog. The documented worst-case total exceeds the 8-second watchdog interval. A watchdog reset can therefore interrupt factory reset after the slots are partially erased.
Feed the watchdog after each successful sector erase. Keep the watchdog interval longer than the worst-case time for one sector erase.
Suggested fix
if (FLASH_SR & 0xF0) { FLASH_SR = 0xF0; FLASH_CR &= ~(1 << 1); flash_lock(); return EOS_ERR_FLASH; } + + eos_hal_watchdog_feed(); }