123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- /*
- * Copyright (c) 2006-2018, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018-05-17 armink the first version
- */
- #include <fal.h>
- #include <string.h>
- #include <stdlib.h>
- /* partition magic word */
- #define FAL_PART_MAGIC_WORD 0x45503130
- #define FAL_PART_MAGIC_WORD_H 0x4550L
- #define FAL_PART_MAGIC_WORD_L 0x3130L
- #define FAL_PART_MAGIC_WROD 0x45503130
- struct part_flash_info
- {
- const struct fal_flash_dev *flash_dev;
- };
- /**
- * FAL partition table config has defined on 'fal_cfg.h'.
- * When this option is disable, it will auto find the partition table on a specified location in flash partition.
- */
- #ifdef FAL_PART_HAS_TABLE_CFG
- /* check partition table definition */
- #if !defined(FAL_PART_TABLE)
- #error "You must defined FAL_PART_TABLE on 'fal_cfg.h'"
- #endif
- /* partition table definition */
- static const struct fal_partition partition_table_def[] = FAL_PART_TABLE;
- static const struct fal_partition *partition_table = NULL;
- /* partition and flash object information cache table */
- static struct part_flash_info part_flash_cache[sizeof(partition_table_def) / sizeof(partition_table_def[0])] = { 0 };
- #else /* FAL_PART_HAS_TABLE_CFG */
- #if !defined(FAL_PART_TABLE_FLASH_DEV_NAME)
- #error "You must defined FAL_PART_TABLE_FLASH_DEV_NAME on 'fal_cfg.h'"
- #endif
- /* check partition table end offset address definition */
- #if !defined(FAL_PART_TABLE_END_OFFSET)
- #error "You must defined FAL_PART_TABLE_END_OFFSET on 'fal_cfg.h'"
- #endif
- static struct fal_partition *partition_table = NULL;
- static struct part_flash_info *part_flash_cache = NULL;
- #endif /* FAL_PART_HAS_TABLE_CFG */
- static uint8_t init_ok = 0;
- static size_t partition_table_len = 0;
- /**
- * print the partition table
- */
- void fal_show_part_table(void)
- {
- char *item1 = "name", *item2 = "flash_dev";
- size_t i, part_name_max = strlen(item1), flash_dev_name_max = strlen(item2);
- const struct fal_partition *part;
- if (partition_table_len)
- {
- for (i = 0; i < partition_table_len; i++)
- {
- part = &partition_table[i];
- if (strlen(part->name) > part_name_max)
- {
- part_name_max = strlen(part->name);
- }
- if (strlen(part->flash_name) > flash_dev_name_max)
- {
- flash_dev_name_max = strlen(part->flash_name);
- }
- }
- }
- log_i("==================== FAL partition table ====================");
- log_i("| %-*.*s | %-*.*s | offset | length |", part_name_max, FAL_DEV_NAME_MAX, item1, flash_dev_name_max,
- FAL_DEV_NAME_MAX, item2);
- log_i("-------------------------------------------------------------");
- for (i = 0; i < partition_table_len; i++)
- {
- #ifdef FAL_PART_HAS_TABLE_CFG
- part = &partition_table[i];
- #else
- part = &partition_table[partition_table_len - i - 1];
- #endif
- log_i("| %-*.*s | %-*.*s | 0x%08lx | 0x%08x |", part_name_max, FAL_DEV_NAME_MAX, part->name, flash_dev_name_max,
- FAL_DEV_NAME_MAX, part->flash_name, part->offset, part->len);
- }
- log_i("=============================================================");
- }
- static int check_and_update_part_cache(const struct fal_partition *table, size_t len)
- {
- const struct fal_flash_dev *flash_dev = NULL;
- size_t i;
- #ifndef FAL_PART_HAS_TABLE_CFG
- if (part_flash_cache)
- {
- FAL_FREE(part_flash_cache);
- }
- part_flash_cache = FAL_MALLOC(len * sizeof(struct part_flash_info));
- if (part_flash_cache == NULL)
- {
- log_e("Initialize failed! No memory for partition table cache");
- return -2;
- }
- #endif
- for (i = 0; i < len; i++)
- {
- flash_dev = fal_flash_device_find(table[i].flash_name);
- if (flash_dev == NULL)
- {
- log_d("Warning: Do NOT found the flash device(%s).", table[i].flash_name);
- continue;
- }
- if (table[i].offset >= (long)flash_dev->len)
- {
- log_e("Initialize failed! Partition(%s) offset address(%ld) out of flash bound(<%d).",
- table[i].name, table[i].offset, flash_dev->len);
- partition_table_len = 0;
- return -1;
- }
- part_flash_cache[i].flash_dev = flash_dev;
- }
- return 0;
- }
- /**
- * Initialize all flash partition on FAL partition table
- *
- * @return partitions total number
- */
- int fal_partition_init(void)
- {
- if (init_ok)
- {
- return partition_table_len;
- }
- #ifdef FAL_PART_HAS_TABLE_CFG
- partition_table = &partition_table_def[0];
- partition_table_len = sizeof(partition_table_def) / sizeof(partition_table_def[0]);
- #else
- /* load partition table from the end address FAL_PART_TABLE_END_OFFSET, error return 0 */
- long part_table_offset = FAL_PART_TABLE_END_OFFSET;
- size_t table_num = 0, table_item_size = 0;
- uint8_t part_table_find_ok = 0;
- uint32_t read_magic_word;
- fal_partition_t new_part = NULL;
- size_t i;
- const struct fal_flash_dev *flash_dev = NULL;
- flash_dev = fal_flash_device_find(FAL_PART_TABLE_FLASH_DEV_NAME);
- if (flash_dev == NULL)
- {
- log_e("Initialize failed! Flash device (%s) NOT found.", FAL_PART_TABLE_FLASH_DEV_NAME);
- goto _exit;
- }
- /* check partition table offset address */
- if (part_table_offset < 0 || part_table_offset >= (long) flash_dev->len)
- {
- log_e("Setting partition table end offset address(%ld) out of flash bound(<%d).", part_table_offset, flash_dev->len);
- goto _exit;
- }
- table_item_size = sizeof(struct fal_partition);
- new_part = (fal_partition_t)FAL_MALLOC(table_item_size);
- if (new_part == NULL)
- {
- log_e("Initialize failed! No memory for table buffer.");
- goto _exit;
- }
- /* find partition table location */
- {
- uint8_t read_buf[64];
- part_table_offset -= sizeof(read_buf);
- while (part_table_offset >= 0)
- {
- if (flash_dev->ops.read(part_table_offset, read_buf, sizeof(read_buf)) > 0)
- {
- /* find magic word in read buf */
- for (i = 0; i < sizeof(read_buf) - sizeof(read_magic_word) + 1; i++)
- {
- read_magic_word = read_buf[0 + i] + (read_buf[1 + i] << 8) + (read_buf[2 + i] << 16) + (read_buf[3 + i] << 24);
- if (read_magic_word == ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
- {
- part_table_find_ok = 1;
- part_table_offset += i;
- log_d("Find the partition table on '%s' offset @0x%08lx.", FAL_PART_TABLE_FLASH_DEV_NAME,
- part_table_offset);
- break;
- }
- }
- }
- else
- {
- /* read failed */
- break;
- }
- if (part_table_find_ok)
- {
- break;
- }
- else
- {
- /* calculate next read buf position */
- if (part_table_offset >= (long)sizeof(read_buf))
- {
- part_table_offset -= sizeof(read_buf);
- part_table_offset += (sizeof(read_magic_word) - 1);
- }
- else if (part_table_offset != 0)
- {
- part_table_offset = 0;
- }
- else
- {
- /* find failed */
- break;
- }
- }
- }
- }
- /* load partition table */
- while (part_table_find_ok)
- {
- memset(new_part, 0x00, table_num);
- if (flash_dev->ops.read(part_table_offset - table_item_size * (table_num), (uint8_t *) new_part,
- table_item_size) < 0)
- {
- log_e("Initialize failed! Flash device (%s) read error!", flash_dev->name);
- table_num = 0;
- break;
- }
- if (new_part->magic_word != ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
- {
- break;
- }
- partition_table = (fal_partition_t) FAL_REALLOC(partition_table, table_item_size * (table_num + 1));
- if (partition_table == NULL)
- {
- log_e("Initialize failed! No memory for partition table");
- table_num = 0;
- break;
- }
- memcpy(partition_table + table_num, new_part, table_item_size);
- table_num++;
- };
- if (table_num == 0)
- {
- log_e("Partition table NOT found on flash: %s (len: %d) from offset: 0x%08x.", FAL_PART_TABLE_FLASH_DEV_NAME,
- FAL_DEV_NAME_MAX, FAL_PART_TABLE_END_OFFSET);
- goto _exit;
- }
- else
- {
- partition_table_len = table_num;
- }
- #endif /* FAL_PART_HAS_TABLE_CFG */
- /* check the partition table device exists */
- if (check_and_update_part_cache(partition_table, partition_table_len) != 0)
- {
- goto _exit;
- }
- init_ok = 1;
- _exit:
- #if FAL_DEBUG
- fal_show_part_table();
- #endif
- #ifndef FAL_PART_HAS_TABLE_CFG
- if (new_part)
- {
- FAL_FREE(new_part);
- }
- #endif /* !FAL_PART_HAS_TABLE_CFG */
- return partition_table_len;
- }
- /**
- * find the partition by name
- *
- * @param name partition name
- *
- * @return != NULL: partition
- * NULL: not found
- */
- const struct fal_partition *fal_partition_find(const char *name)
- {
- assert(init_ok);
- size_t i;
- for (i = 0; i < partition_table_len; i++)
- {
- if (!strcmp(name, partition_table[i].name))
- {
- return &partition_table[i];
- }
- }
- return NULL;
- }
- static const struct fal_flash_dev *flash_device_find_by_part(const struct fal_partition *part)
- {
- assert(part >= partition_table);
- assert(part <= &partition_table[partition_table_len - 1]);
- return part_flash_cache[part - partition_table].flash_dev;
- }
- /**
- * get the partition table
- *
- * @param len return the partition table length
- *
- * @return partition table
- */
- const struct fal_partition *fal_get_partition_table(size_t *len)
- {
- assert(init_ok);
- assert(len);
- *len = partition_table_len;
- return partition_table;
- }
- /**
- * set partition table temporarily
- * This setting will modify the partition table temporarily, the setting will be lost after restart.
- *
- * @param table partition table
- * @param len partition table length
- */
- void fal_set_partition_table_temp(struct fal_partition *table, size_t len)
- {
- assert(init_ok);
- assert(table);
- check_and_update_part_cache(table, len);
- partition_table_len = len;
- partition_table = table;
- }
- /**
- * read data from partition
- *
- * @param part partition
- * @param addr relative address for partition
- * @param buf read buffer
- * @param size read size
- *
- * @return >= 0: successful read data size
- * -1: error
- */
- int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
- {
- int ret = 0;
- const struct fal_flash_dev *flash_dev = NULL;
- assert(part);
- assert(buf);
- if (addr + size > part->len)
- {
- log_e("Partition read error! Partition address out of bound.");
- return -1;
- }
- flash_dev = flash_device_find_by_part(part);
- if (flash_dev == NULL)
- {
- log_e("Partition read error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
- return -1;
- }
- ret = flash_dev->ops.read(part->offset + addr, buf, size);
- if (ret < 0)
- {
- log_e("Partition read error! Flash device(%s) read error!", part->flash_name);
- }
- return ret;
- }
- /**
- * write data to partition
- *
- * @param part partition
- * @param addr relative address for partition
- * @param buf write buffer
- * @param size write size
- *
- * @return >= 0: successful write data size
- * -1: error
- */
- int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
- {
- int ret = 0;
- const struct fal_flash_dev *flash_dev = NULL;
- assert(part);
- assert(buf);
- if (addr + size > part->len)
- {
- log_e("Partition write error! Partition address out of bound.");
- return -1;
- }
- flash_dev = flash_device_find_by_part(part);
- if (flash_dev == NULL)
- {
- log_e("Partition write error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
- return -1;
- }
- ret = flash_dev->ops.write(part->offset + addr, buf, size);
- if (ret < 0)
- {
- log_e("Partition write error! Flash device(%s) write error!", part->flash_name);
- }
- return ret;
- }
- /**
- * erase partition data
- *
- * @param part partition
- * @param addr relative address for partition
- * @param size erase size
- *
- * @return >= 0: successful erased data size
- * -1: error
- */
- int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
- {
- int ret = 0;
- const struct fal_flash_dev *flash_dev = NULL;
- assert(part);
- if (addr + size > part->len)
- {
- log_e("Partition erase error! Partition address out of bound.");
- return -1;
- }
- flash_dev = flash_device_find_by_part(part);
- if (flash_dev == NULL)
- {
- log_e("Partition erase error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
- return -1;
- }
- ret = flash_dev->ops.erase(part->offset + addr, size);
- if (ret < 0)
- {
- log_e("Partition erase error! Flash device(%s) erase error!", part->flash_name);
- }
- return ret;
- }
- /**
- * erase partition all data
- *
- * @param part partition
- *
- * @return >= 0: successful erased data size
- * -1: error
- */
- int fal_partition_erase_all(const struct fal_partition *part)
- {
- return fal_partition_erase(part, 0, part->len);
- }
|