-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
drivers: disk_flash: Create disk_flash driver #62527
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.
Hello @kica-z, and thank you very much for your first pull request to the Zephyr project!
A project maintainer just triggered our CI pipeline to run it against your PR and ensure it's compliant and doesn't cause any issues. You might want to take this opportunity to review the project's Contributor Expectations and make any updates to your pull request if necessary. 😊
Hi and thanks!
I am no expert but this does sound useful to me.
Yes, please create a Kconfig option for this
I hope @de-nordic can answer that. |
I guess many things have no use unless you show how they work.
It should be configurable, but not also that SD card is something that is removable so this needs to be addressed.
Developers working on Disk Access have recently moved a lot of settings to DTS where they have become property of Disk nodes.
COND_CODE_1/0 macros. |
@kica-z, thanks for the PR this feature would indeed be highly appreciated. One difficulty I see: the proposed PR is kind of making a partition on disk by specifying the offset and the size. But the other systems using the disk (fatfs, littlefs) are not aware that this is happening, how is this handled ? |
@carlescufi, @de-nordic I moved the disk-sector-size as well as the init-level of the driver into the dts so that it can be adjusted for each instance individually. @de-nordic Regarding the SD mcuboot example I can try to add one but this will take some time since for our project we use the nordic tools and the nrf fork so some adjustment is necessary. @de-nordic What do you mean when you say keeping in mind that the sd-card is removable. Should not access to the disk-api fail as soon as the sd-card is disconnected? What would you expect from the driver in this scenario? Wait for it to reapear and reinit with the new sector size? Or just check every call if the sector buffer is sufficient? @Laczen Currently we in the project create a separate partition on the sd-card for this and manually take care that there is no overlap between the fs and the disk_flash. It is true, that when the user defines overlapping partitions with e.g. fatfs,littlefs this will not be detected and lead to errors. Do you think there has to be a mechanism to detect this instead of leaving this to the user? |
I don't see how this can be done. The sd-card size is unknown (maybe this is what @de-nordic is referring to with the removable sd-card) and there is no partitioning of sd-cards (correct me if I'm wrong). |
@Laczen we do actually partition our sd-card. In our project fatfs uses the |
What does zephyr report about this disk ? Can it detect the D partition and the OEM partition ? How is the fatfs limited to the |
@Laczen The disk-api reports the full size of the sd-card no matter what partitions are defined on the card (calculated by sector_count * sector_size). Fatfs however detects the filesystem in the first partition and reports only the size of that partition as its size (f_blocks * f_frsize). So at least in this constellation (fs partition first -> oem after) it seems to work as intended. The disk_flash driver of course still needs to be tuned to write into the oem partition as there is no autodetection or similar implemented here. |
@kica-z it seems fragile to rely on the existence of a fatfs partition to allow this to work. At first glance this wouldn't be supported when littlefs is used on the disk. |
@Laczen I am not quite sure I understood your comment correctly so correct me if i misinterpreted it: I don't think the driver is responsible for supporting the user in configuring his block device. So in conclusion the driver is not relying on a fatfs partition to be present. The user simply has to configure his setup according to his needs which might then need a fatfs or littlefs that is not using the entire diskspace of a disk. I however agree that this might be a topic for documentation in order to support the user with using this driver in parallel to a fs. |
I don't think this is true for littlefs, it always uses the entire disk. I also doubt that it is possible to create a fatfs partition in zephyr that uses only part of the disk, so if a mkfs is done in zephyr this will also consume the whole disk. |
@Laczen I stand corrected littlefs really seems to not support partially using a disk. I misinterpreted a documentation entry. I don't know mkfs of zephyr well enough to make a statement regarding the possibility of not using the whole disk. It is quite possible that this is not possible. However you could circumvent this problem by defining two disk_flash devices and running littlefs/fatfs on one of them as both FS also support the flash_api. This way there would be no overlap. I have however not tested this yet. But as already mentioned I think the support of a filesystem on the same disk is not a requirement for this driver to be usefull. It would definitely be a nice to have though. |
This would indeed be a solution to avoid the problem. But I don't think it is possible at the moment to "split" or partition a disk. @danieldegrasse are there any plans to allow splitting or partitioning a disk (e.g. some fixed size raw zephyr-disk, and then a variable sized disk for a filesystem) ?
I agree it would be nice to have this, |
No plans currently from me. I expect this could be achieved by defining an emulated disk driver that simply reported a different sector count than the underlying disk device it was exposing. Multiple disk drivers like this could be combined to "parition" a disk with the current API As far as the PR itself, this looks like a useful addition. Although the only use case I'm aware of is MCUBoot, there are still likely cases where users want to use MCUBoot as the bootloader but store boot images on a SD or eMMC device |
I thought about this too and think it could be a useful addition. Maybe even add a devicetree entry |
f7228a7
to
9abd7d4
Compare
379e1ee
to
72cbd6d
Compare
@jfischer-no @carlescufi What is the status here? Is there something I am missing before a new review can be done? |
drivers/flash/Kconfig.disk
Outdated
# Copyright (c) 2023 Endress+Hauser AG | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
config FLASH_DRIVER_DISK |
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.
There are few inconsistencies, compatibility is "zephyr,disk-flash", let's align everything to it, Kconfig.disk -> Kconfig.disk_flash, flash_disk.c -> disk_flash.c, CONFIG_FLASH_DRIVER_DISK -> CONFIG_DISK_FLASH_DRIVER or CONFIG_DISK_FLASH ....
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.
Renamed for better consistency
drivers/flash/flash_disk.c
Outdated
struct flash_disk_dev_data { | ||
#if defined(CONFIG_MULTITHREADING) | ||
struct k_sem sem; | ||
#endif | ||
char *const sector_buf; | ||
uint16_t const sector_buf_size; | ||
uint32_t disk_total_sector_cnt; | ||
uint32_t disk_sector_size; | ||
}; | ||
|
||
struct flash_disk_dev_config { |
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.
struct disk_flash_data, struct disk_flash_config, see comment about inconsistent naming, it is obvious what these are, no need to have dev in name.
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.
Adjusted
drivers/flash/flash_disk.c
Outdated
const struct flash_disk_dev_config *cfg; | ||
uint32_t write_cursor = 0; | ||
|
||
LOG_DBG("%s called", __func__); |
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.
Please remove func, use https://docs.zephyrproject.org/latest/kconfig.html#CONFIG_LOG_FUNC_NAME_PREFIX_DBG, do not use LOG_DBG for tracing.
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.
Removed
drivers/flash/flash_disk.c
Outdated
{ | ||
int ret = 0; | ||
char *dst_buf = (char *)dst; | ||
struct flash_disk_dev_data *data; |
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.
Proper drivers would do:
const struct disk_flash_config *cfg = dev->config;
struct disk_flash_data *data = dev->data;
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 moved the pointer assignment as mentioned here.
drivers/flash/flash_disk.c
Outdated
static int flash_disk_read(const struct device *dev, off_t offset, void *dst, size_t len) | ||
{ | ||
int ret = 0; | ||
char *dst_buf = (char *)dst; |
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.
uint8_t *dst_buf = dst;
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.
Adjusted
drivers/flash/flash_disk.c
Outdated
memcpy(&dst_buf[write_cursor], &data->sector_buf[read_padding], len_write); | ||
write_cursor += len_write; | ||
} | ||
release_device: |
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.
}
release_device:
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.
Adjusted
/* | ||
* Copyright (c) 2023 Endress+Hauser AG | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/device.h> | ||
#include <zephyr/drivers/flash.h> | ||
#include <zephyr/logging/log.h> | ||
|
||
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_disk_flash) | ||
#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_disk_flash) | ||
#else | ||
#error Unsupported flash driver | ||
#define FLASH_NODE DT_INVALID_NODE | ||
#endif | ||
|
||
LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); | ||
|
||
int main(void) | ||
{ | ||
int res = 0; | ||
const struct device *const dev = DEVICE_DT_GET(FLASH_NODE); | ||
|
||
if (!device_is_ready(dev)) { | ||
LOG_ERR("%s: device not ready\n", dev->name); | ||
return 0; | ||
} | ||
|
||
char testWrite[] = "This was written to flash_disk."; | ||
char testRead[sizeof(testWrite)]; | ||
|
||
res = flash_write(dev, (off_t)20, testWrite, sizeof(testWrite)); | ||
if (res != 0) { | ||
LOG_ERR("Flash write failed"); | ||
} | ||
|
||
res = flash_read(dev, (off_t)20, testRead, sizeof(testRead)); | ||
if (res != 0) { | ||
LOG_ERR("Flash read failed"); | ||
} | ||
|
||
if (strcmp(testWrite, testRead) != 0) { | ||
LOG_ERR("Flash read return wrong data: \"%s\" != \"%s\"", testWrite, testRead); | ||
} else { | ||
LOG_INF("Read/Write test successful"); | ||
} | ||
|
||
return 0; | ||
} |
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.
There is no benefit to adding a specific sample for a driver that uses a generic API. This should work fine with e.g. samples/drivers/flash_shell
(just move app.overlay to samples/drivers/flash_shell/disk_flash.overlay).
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 removed the sample and added overlays to work with the flash_shell
sample.
-> Can be build by running: west build -b qemu_x86 samples/drivers/flash_shell/ -DDTC_OVERLAY_FILE=disk_flash.overlay -DOVERLAY_CONFIG=disk_flash.conf
samples/drivers/flash_disk/prj.conf
Outdated
CONFIG_MINIMAL_LIBC=y | ||
|
||
# Enable flash on disk | ||
CONFIG_FLASH_DRIVER_DISK=y |
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.
Should not be explicitly enabled because of:
default y
depends on DT_HAS_ZEPHYR_DISK_FLASH_ENABLED
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.
Removed
/ { | ||
ramdisk0 { | ||
compatible = "zephyr,ram-disk"; | ||
disk-name = "DISK1"; |
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.
disk-name = "DISK0"; or disk-name = "ramdisk"; ...
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.
Renamed
disk-sector-size: | ||
type: int | ||
description: the sector size in byte of the underlying disk to be used | ||
required: true | ||
disk-offset: | ||
type: int | ||
description: > | ||
offset on the disk in bytes. If the offset is 10 the 10th byte will | ||
be the first one used. | ||
default: 0 |
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.
The information is already there, there must not be an other property to describe the same, please take a look at DT_INST_PROP_BY_PHANDLE, ping me if you need help with that.
72cbd6d
to
cf32448
Compare
@jfischer-no Except for the point you mentioned with the |
83966c7
to
3f0c0ed
Compare
uint32_t write_cursor = cfg->disk_offset + offset + read_cursor; | ||
uint32_t write_sector = write_cursor / data->disk_sector_size; | ||
uint32_t write_padding = write_cursor % data->disk_sector_size; | ||
uint32_t len_write = (len - read_cursor); |
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 do not think it is very efficient to keep recalculating these in loop.
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.
@de-nordic
I agree that this is not very efficient but I don't see a way around it since the driver allows arbitrary write/read sizes and does not need to be sector aligned with the disk.
I understood you believe, that read/write/erase granularity must be equal to the underlying disk device. The idea of this flash driver is to offer a read/write/erase granularity of a single byte on top of a disk with arbitrary sector sizes. So operations typically:
-read sector,
-update sector,
-write sector,
-loop
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.
That is bad. This means that half of sector may belong to something else.
And another thing is that SD card is block device. Read/write and emulated erase happens in blocks.
If you modify single byte what will happen is that entire sector needs to be re-written by a controller.
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.
But unless done this way, how would you simulate a flash with potentially different properties then underlying device?
Would you prefer, that flash_disk
inherits properties from underlying device? If so, it would probably no longer be suitable for our use-case.
I see the following possibilities:
- be at maximum permissive granularity (1 byte, current proposal)
- be user configurable (with Kconfig?)
- same as underlying device (severely limiting the usefulness of it to emulate a device with different properties on top of another)
Of course with 1. it is expected, that caller calls with big junks also. With 3. it is not possible to use as secondary partition for mcuboot
if underlying device has different properties to main flash. Which would nullify the main benefit of the flash_disk
module.
Or am I missing something? Can primary and secondary partition for mcuboot have different properties?
If yes, then of course, the story is entirely different.
Thanks for the quick responses and instructing reviews.
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.
Or did I completely miss your point and you suggestions is just to improve simply the code to:
- handle initial (potentially misaligned) sector
- handle most sectors with single call to
disk_access
- handle final (potentially misaligned) 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.
Thank you for elaborating your concerns, I think, that I understand better now. Did I understand your concerns correclty, that:
- The trailer containing meta-information about the slot is written at the end of each slot. So there is a trailer at the end of the secondary slot on the flash_disk. Did I understand correctly, that this would mean, that whereas on a flash the trailer is erased once and then progressively written the flash-disk would need to read-update-write the sector containing the trailer with each status update which concerns you because of too much wear on disks without wear-leveling?
- You are worried, that the write of a sector is not an atomic operation, such that it might end up being half-written for example in case of power-loss? Leading to possible damage to the system.
There is another issue that there is very small chance that you can break the status update when record is added, but when you break it while write block happens, what will happen is that there will not longer be record of any swap happening and, at the same time, you will have two damaged slots (partially swapped).
Are you refering to the fact, that swapping might fail when using swap-using-move
on an image that is too big (100% of available space) because it can not move down the primary imgage block-wise when there is no free block? Whereas this can not happen when using swap-using-scratch
? Or is there another reason for recommending swap using scratch
?
Thanks
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.
Both with swap-using-move
and swap-using-scratch
the result of a block move is written to flash. When using a disk and the write of the last sector fails you could loose all information about the process (all information is on one disk sector), while on flash only the last block move information might be incorrect. If all information is lost there is no way to continue the swap and you are left with an unrecoverable system.
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.
Understood.
So it would not matter which strategy here?
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.
Yes, the strategy does not matter.
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.
Shouldn't the danger of sector write fail be lowered since when not written entirely the sd-card should still contain a partially correct sector? Or how is the status of the swap tracked? By settings bytes to 0?
Also I do not currently see any mitigation for the two problems brought up in this thread. Neither for the problem with the high disk usage due to sector overwrites nor for the problem with partial writes. Do you see any mitigation possibilites here or what would/should be the way forward?
data->disk_sector_size); | ||
} | ||
|
||
disk_size = data->disk_sector_size * data->disk_total_sector_cnt; |
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.
size_t
may not be enough to hold the value. On 32 bit platform that is up to 4G. Is it possible that larger devices would be used?
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.
You are right. There is absolutely a possibility that large disks could be used since this driver supports partitioning. I adjusted this.
memset(&data->sector_buf[write_padding], | ||
cfg->flash_parameters.erase_value, | ||
len_write); |
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.
You could do that once, before entering the loop.
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.
Since the erase supports arbitrary size and does not need to be aligned with the sector of the disk partial sectors need to be erased. Therefore I don't currently see a possibility to do this outside the loop.
uint32_t write_cursor = cfg->disk_offset + offset + read_cursor; | ||
uint32_t write_sector = write_cursor / data->disk_sector_size; | ||
uint32_t write_padding = write_cursor % data->disk_sector_size; | ||
uint32_t len_write = (size - read_cursor); |
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 guess that both cursors will be moved by sector size or multiple of that? Looks like too much arithmetic for adding sector 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.
Not necessarily moved by sector size since the driver is not dependent on the underlying disk sector size partial sectors may be written or read. As such I think that much arithmetic is needed.
drivers/flash/disk_flash.c
Outdated
.flash_size = DT_INST_PROP(index, size), \ | ||
.flash_parameters = \ | ||
{ \ | ||
.write_block_size = 1, \ |
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 do not think this is good idea. If you try to loop writing data with such block size, what would happen is that you would probably get one sector erased and rewritten by number of bytes in sector. Or SD controller, if it is something super smart, will do number of sector reallocations equal to sector size in bytes.
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 do not completely understand this comment but I had both write_block size and erase_size as DT property before but was told that this should not be necessary:
Why would this need to be configurable? The underlying disk controller should always support 1 byte block writes
As I mentioned before this driver aims to be as independent from the underlying disk block size as possible and does currently support arbitrary read/write/erase sizes.
drivers/flash/disk_flash.c
Outdated
(.fpl = \ | ||
{ \ | ||
.pages_count = DT_INST_PROP(index, size), \ | ||
.pages_size = 1 \ |
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.
Erase at least by sector 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.
Is there a reason to make this driver dependent on the disk sector size? This driver currently supports arbitrary write/read/erase sizes independent from the underlying disk.
drivers/flash/disk_flash.c
Outdated
if (read_sector < 0 || read_sector >= data->disk_total_sector_cnt) { | ||
ret = -EINVAL; | ||
goto release_device; | ||
} |
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.
Shouldn't the range be tested before entering the loop?
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.
You are right. This check actually is not even needed anymore. With the check_boundary
function we check that the read/write is within the defined flash partition and in disk_flash_init
we check that the partition is within the underlying disk.
drivers/flash/disk_flash.c
Outdated
if (write_sector < 0 || write_sector >= data->disk_total_sector_cnt) { | ||
LOG_ERR("Sector out of bounds"); | ||
ret = -EINVAL; | ||
goto release_device; | ||
} |
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.
Shouldn't the range be tested before entering the loop?
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.
You are right. This check actually is not even needed anymore. With the check_boundary
function we check that the read/write is within the defined flash partition and in disk_flash_init
we check that the partition is within the underlying disk.
3f0c0ed
to
c0de5b3
Compare
c0de5b3
to
c54b263
Compare
Added page-size as DTS property again since it is needed for mcuboot to be able to match the primary flash page size. Also defined the size in bits again since nrf-partition-manager gets confused otherwise (also done like this in other flash drivers). |
0d4e9ed
to
8c9a868
Compare
Neither MCUBoot nor nrf-partition-manager (?) are Zephyr projects; there should be nothing specific to them in a Zephyr RTOS driver. |
@jfischer-no You are correct of course but these softwares showed the errors/shortcomings the driver still was having. Defining disk size in bits is done in other flash drivers as well so I merely adjusted the driver to better fit in with those drivers. Also being able to define the page size is a valuable additon for a flash-emulator no matter if used with mcuboot or not. |
Create a driver that emulates a flash storage on the disk api. This enables e.g. using an spi SD-Card as secondary partition for mcuboot. Signed-off-by: Carlo Kirchmeier <[email protected]>
8c9a868
to
52d3b7f
Compare
This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time. |
For our project we created a driver that emulates a flash on an underlying disk. We use this to emulate the secondary partition of mcuboot on an spi SD-Card. Since this driver could be usefull to some people we would like to upstream it.
Before that there are however some questions I have since this is the first zephyr driver I develop:
init_level
of the driver be configurable? Currently it isAPPLICATION
since theramdisk
driver is initialized atAPPLICATION
level. If yes how should I go about that? Add it to the devicetree?FLASH_DISK_BUFFER_SIZE
be evaluated at compile time from the underlying disk? Or is there a way to determine and allocate it during runtime without having to define a Kconfig?flash_pages
?