-
Notifications
You must be signed in to change notification settings - Fork 178
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
[STM32F4] Add bootloader overwrite self-protection #189
[STM32F4] Add bootloader overwrite self-protection #189
Conversation
c133e1d
to
21ab90b
Compare
Ready for review. |
767cb48
to
23a32aa
Compare
I have written a small program that is apply-able as a UF2 image that will unprotected the flash sectors again and jump to the built-in DFU bootloader of the STM32F411. This acts as unlocker key to update or overwrite the whole flash. The project is called tinyuf2-unlocker |
Hi thank you for your PR. I am currently on TET (Lunar New Year) holiday. Will check this out later on |
Thanks, have a great holiday! |
cd92c9c
to
4058572
Compare
Hmm, is reserving the whole 64KB block for the bootloader intended? Some of these 16KB flash sectors could be useful for storing some firmware settings (unfortunately, on STM32F4 other flash sectors are much larger, therefore rewriting them at runtime is problematic). One of recent QMK PRs actually tried to add a board which uses tinyuf2, but assumes that only sectors 0 and 1 are occupied by the bootloader, and therefore uses sector 2 for EEPROM emulation. Setting the protection flags for sectors 0…3 irrespective of the actual bootloader size would break such usage. |
for eeprom emulation they should use the last block in memory |
@KarlK90 Thanks for this PR. https://github.com/adafruit/tinyuf2/blob/master/ports/stm32f4/linker/stm32f4.ld#L47 Am i missing something ? |
83d561a
to
80dfdb9
Compare
No you are completely right, I took the number from the QMK linker file which starts the usable flash sections at 64kb offset. I didn't cross reference it with the tinyuf2 linker script. Fixed the bootloader protection by only locking the first two sectors. |
80dfdb9
to
f126649
Compare
Although the tinyuf2 bootloader assumes that the main app starts at a 64kb offset, so technically there is a 32kb gap... https://github.com/adafruit/tinyuf2/blob/master/ports/stm32f4/boards.h#L38 |
f126649
to
544e302
Compare
Tinyuf2 occupies the first two flash sectors in the whole stm32f4 family. These are write protected by setting the option bytes nWRP in the flash peripheral when booting the board. This is done to always prevent tinyuf2 from overwriting itself by accident. By default the write protection is disabled by setting PROTECT_BOOTLOADER to 0. Disabling the write protection again can be done via DFU or SWD with STM32CubeProg or openocd.
544e302
to
1633e6c
Compare
Friendly ping @hathach |
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.
Sorry for late response, after TET, I kind of forget about this. This is a great PR, everything look great. And can be merged as it is, though I would like to include the tinyuf2-unlocker
in this PR as well if possible.
The reason is for self-update via uf2, basically an special that contains bootloader binary in an array bytes and write that to the bootloader flash region. Currently it is not supported on stm32f4 port, but I think this is a good chance to also include it to
I have checked out your tinyuf2-unlocker but unfortunately I don't understand rust. Would you mind adding the unlock code, ideally it would be
void board_self_update(const uint8_t * bootloader_bin, uint32_t bootloader_len)
{
(void) bootloader_bin;
(void) bootloader_len;
board_flash_protect_bootloader(false); // unlock
// write booloader_bin to sector 0,1 since we are currently running as application (this can be its own PR later on).
board_flash_protect_bootloader(true); // lock
}
If you are considering to make Implementing the self-update procedure on MCUs like that would still be possible, but would require that the bootloader does not reapply the flash protection when the firmware reboot is requested (this seems to be the case with the current code, because |
@sigprof thank for your input, do you think we can use one of the DBL_TAP_MAGIC_PROTECTION_OFF as way to go around the infinite loop and continue to with the update once protection if off. It is definitely need some handshake between self-update app and bootloader. However, I think we should stick with simplest way that work with F4 first, and generalize/refactor to other family later on. Although It may take more effort overall, it will ensure we don't write more code than we need. |
…return bool rename PROTECT_BOOTLOADER to global TINYUF2_PROTECT_BOOTLOADER option
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.
I have updated the board_flash_protect_bootloader to take bool argument for protect/un-protect. I am trying to also get self-update to work with boot protection as well, however, I realize that self-update need quite a bit of additional changes and requires an cmsis f4 update to address the issue with vector table. I will merge this first and make an PR for self-update afterwards. Thank you very much for your effort and patience on this PR.
PS: esp32 build failed is already resolved in master, it would be ok to merge.
No problem, hope you had a good TET 🎉
I was pretty busy in the last weeks that is why I didn't respond earlier. Thanks for the merge and taking over from here! Happy that I could provide a good starting point for the self-update feature. |
@KarlK90 no problem at all, I fully understand the busy with other works well enough. Btw, I struggled a bit with old cmsis f4, since its system_stm32f4xx.c reset the vector table (SCB->VTOR) to default 0x08000000 (incorrect). Just update to latest cmsis, the later skip statement if not defined I am putting thing up together, self-update may not be related to protected bootloader, but we must get them running together before enabling it. Otherwise we will have a chance to lock the bootloader which could require user to run various code to unlock/flash and risk bricking the board. |
It's frustrating when I try to erase tinyuf2 after flashed it. No tool provided in the first place. Follow tinyuf2-unlocker guide but the build artifact doesn't work at all. Try to disable write protection and erase via STM32Cube, the blackpill drive pops again. Any ideas? |
This is what I encounter now. Unfortunately I only have one CMSIS-DAP so I cannot update its firmware (which must be done from the host over another downloader). I found pyocd could erase listed sectors with
Is this achievable, and which sector shall I pass?
|
@myst729 please open a new issue for your problem, this PR is merged and closed. |
For review read the commits in separation
Driven by a remark that bootloader protection is still pending I implemented it for the STM32F4 family.
For broader use a new board level function is introduced
board_flash_protect_bootloader()
. All other ports are currently implemented as stubs.On the STM32F4 family tinyuf2 occupies the first two flash sectors. The overwrite protection is enabled by setting the option bytes nWRP register in the flash peripheral. This is done when booting the board to always prevent tinyuf2 being overwritten. Also this is also only done for the bits that haven't been already processed to not wear out the memory.
@hathach I'm not sure if this logic should be included for all ports and moved to tinyuf2's
main.c
?By default the overwrite protection is disabled by setting
PROTECT_BOOTLOADER
to 0.Disabling the write protection again i.e. changing the nWRP to 1 again, can be done with a simple program called tinyuf2-unlocker that can be uploaded as an UF2 image or has do be done externally via DFU or SWD with STM32CubeProg or openocd.