-
-
Notifications
You must be signed in to change notification settings - Fork 40.1k
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
Fix flash wear leveling sector calculation #24776
base: master
Are you sure you want to change the base?
Conversation
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.
Looks like this code won't work on STM32F4xx (and any other chips with non-uniform flash sectors), because flashGetSectorOffset(flash, desc->sectors_count)
would read beyond the end of the desc->sectors
array. So the code which finds the actual number of available flash sectors needs to be careful to avoid passing invalid sector numbers to ChibiOS functions.
flash_sector_t last_sector = desc->sectors_count - WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT; | ||
|
||
// skip sectors that are past the actual flash size | ||
while (flashGetSectorOffset(flash, last_sector) >= flash_size) { | ||
last_sector--; | ||
} |
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.
Applying WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT
first looks wrong (probably whoever added this code assumed that desc->sectors_count
should be correct, but this might not be the case). There are no real users of that option in the repo though.
@@ -84,12 +84,14 @@ bool backing_store_init(void) { | |||
|
|||
// Work out how many sectors we want to use, working backwards from the end of the flash | |||
flash_sector_t last_sector = desc->sectors_count - WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT; | |||
|
|||
// skip sectors that are past the actual flash size | |||
while (flashGetSectorOffset(flash, last_sector) >= flash_size) { |
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.
This code would trigger undefined behavior on the first iteration if EFL uses the desc->sectors
array (e.g., on STM32F4xx), because the valid range of sector numbers is [0…desc->sectors_count-1
]. The original code (before it had been broken by the change which added WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT
) did not have this problem, because it subtracted at least 1 from desc->sectors_count
.
Also should we guard against more pathological cases, like no free sectors, or even a sector being partially out of range of the reported flash size? Although with the current error handling the only option is apparently to halt with a message that nobody would see.
* subtract WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT after getting last_sector * don't pass value beyond desc->sectors_count to flashGetSectorOffset * add checks if not enough flash sectors are available
Thanks for the review. I fixed the issues you mentioned and added some additional checks. |
Description
Currently the calculation of the last usable flash sector doesn't work properly if
last_sector
starts beyond the end of the actual flash size:qmk_firmware/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
Lines 87 to 92 in 172c349
Here the
last_sector
is calculated from thefirst_sector
but alsoi
is included in the calculation. Buti
is incremented in each loop iteration and thus an increasing offset is added.The solution here is to first calculate the number of the last usable sector and then use another loop to calculate the first sector.
Types of Changes
Issues Fixed or Closed by This PR
Checklist