diff --git a/.gitmodules b/.gitmodules index 59ef5f3..8772234 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "components/mch2022-rp2040"] path = components/mch2022-rp2040 url = https://github.com/badgeteam/esp32-component-mch2022-rp2040.git +[submodule "components/esp32-component-appfs"] + path = components/appfs + url = https://github.com/badgeteam/esp32-component-appfs.git diff --git a/bootloader_components/main b/bootloader_components/main new file mode 120000 index 0000000..d14493a --- /dev/null +++ b/bootloader_components/main @@ -0,0 +1 @@ +../components/appfs/bootloader_main \ No newline at end of file diff --git a/bootloader_components/main/CMakeLists.txt b/bootloader_components/main/CMakeLists.txt deleted file mode 100644 index d5149ed..0000000 --- a/bootloader_components/main/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -idf_component_register(SRCS "bootloader_start.c" "appfs_flashfunctions_wrapper.c" - REQUIRES bootloader bootloader_support appfs) - -idf_build_get_property(target IDF_TARGET) -# Use the linker script files from the actual bootloader -set(scripts "${IDF_PATH}/components/bootloader/subproject/main/ld/${target}/bootloader.ld" - "${IDF_PATH}/components/bootloader/subproject/main/ld/${target}/bootloader.rom.ld") - -target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}") - -target_link_libraries(${COMPONENT_LIB} INTERFACE - "-Wl,--wrap=bootloader_flash_read" - "-Wl,--wrap=bootloader_mmap" - "-Wl,--wrap=bootloader_munmap" - "-Wl,--wrap=bootloader_console_deinit" - ) - diff --git a/bootloader_components/main/appfs_flashfunctions_wrapper.c b/bootloader_components/main/appfs_flashfunctions_wrapper.c deleted file mode 100644 index d5f7fab..0000000 --- a/bootloader_components/main/appfs_flashfunctions_wrapper.c +++ /dev/null @@ -1,177 +0,0 @@ -/* -These functions wrap the flash read and mmap functions. The idea is that normally, they will run the real -functions. However, after appfs_wrapper_init is called with an appfs file and a flash range, any -call to these functions in that range will be redirected to the appfs functions that do the same. -The idea is that this changes the 'view' of that flash range from an (for the rest of the bootloader) -ununderstandable appfs struct mess, to one that looks the same as it would when the selected file -would be directly flashed to the partition. The nice thing here is that we can use the rest of the -bootloader verbatim, without having to modify it. - -Not we assume the ovl_start and ovl_end match the position and size of the appfs partition; we use that -if we actually boot an app. - -Note that IRAM_ATTR is used here to make sure the functions that are used when/after the app loadable -segments are loaded, won't be overwritten. The IRAM_ATTR in the bootloader code dumps the function -in the loader segment instead of in random IRAM. -*/ - -#ifdef BOOTLOADER_BUILD - -#include "appfs.h" -#include "esp_log.h" -#include "esp_attr.h" -#include "esp_app_format.h" -#include "soc/soc_memory_types.h" -#include "soc/soc_caps.h" -#include -#include "soc/dport_reg.h" -#include "esp32/rom/cache.h" - - -static const char *TAG="appfs_wrapper"; - -static appfs_handle_t file_handle=APPFS_INVALID_FD; -static size_t ovl_start, ovl_size; - -void appfs_wrapper_init(appfs_handle_t handle, size_t part_start, size_t part_size) { - file_handle=handle; - ovl_start=part_start; - ovl_size=part_size; -} - -void appfs_wrapper_deinit() { - file_handle=APPFS_INVALID_FD; -} - -//These are the actual functions. -esp_err_t __real_bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt); -const void *__real_bootloader_mmap(uint32_t src_addr, uint32_t size); -void __real_bootloader_munmap(const void *mapping); -void __real_bootloader_console_deinit(); - - -static bool was_mmapped_to_appfs=false; - -IRAM_ATTR const void *__wrap_bootloader_mmap(uint32_t src_addr, uint32_t size) { - if (file_handle!=APPFS_INVALID_FD && src_addr>=ovl_start && src_addr+size=ovl_start && src_addr+size0x%X, %d bytes", src_addr, (int)dest, size); - return appfs_bootloader_read(file_handle, src_addr-ovl_start, dest, size); - } else { - return __real_bootloader_flash_read(src_addr, dest, size, allow_decrypt); - } -} - -IRAM_ATTR static bool should_map(uint32_t load_addr) { - return (load_addr >= SOC_IROM_LOW && load_addr < SOC_IROM_HIGH) - || (load_addr >= SOC_DROM_LOW && load_addr < SOC_DROM_HIGH); -} - -//Note: when this is called, everything to verify and load the app has already been done *EXCEPT* the MMU -//mapping. That is done, but with wrong addresses. We need to re-do that here and then call into -//the app. -static IRAM_ATTR void mmap_and_start_app() { - ESP_LOGD(TAG, "mmap_and_start_app()"); - //First, check if we actually need to do this. If loading the appfs app failed (e.g. because it - //got corrupted), the previous routine will fall back to e.g. the factory app. If we would - //adjust the MMU assuming the appfs app had loaded, we would crash. - //Note that this is ESP32-specific. - for (int i = 0; i < DPORT_FLASH_MMU_TABLE_SIZE; i++) { - if (DPORT_PRO_FLASH_MMU_TABLE[i] != DPORT_FLASH_MMU_TABLE_INVALID_VAL) { - int page=DPORT_PRO_FLASH_MMU_TABLE[i]&255; - int addr=page*0x10000; - if (addrovl_start+ovl_size) { - ESP_LOGI(TAG, "Not booting appfs app; not adjusting mmu."); - return; - } - } - } - - //Undo bootloader mapping. If we don't call this, the rest of the code thinks there's still - //something mapped. Note that for now the address doesn't matter, we feed it 0. - __real_bootloader_munmap(0); - - //Map the executable file so we can read its header. - uint8_t *appBytes=appfsBlMmap(file_handle); - const esp_image_header_t *hdr=(const esp_image_header_t*)appBytes; - uint32_t entry_addr=hdr->entry_addr; - - AppfsBlRegionToMap mapRegions[8]; - int noMaps=0; - uint8_t *pstart=appBytes+sizeof(esp_image_header_t); - uint8_t *p=pstart; - for (int i=0; isegment_count; i++) { - esp_image_segment_header_t *shdr=(esp_image_segment_header_t*)p; - p+=sizeof(esp_image_segment_header_t); - if (should_map(shdr->load_addr)) { - mapRegions[noMaps].fileAddr=p-appBytes; - mapRegions[noMaps].mapAddr=shdr->load_addr; - mapRegions[noMaps].length=shdr->data_len; - noMaps++; - ESP_LOGI(TAG, "Segment %d: map to %X size %X", i, shdr->load_addr, shdr->data_len); - } else { - ESP_LOGI(TAG, "Segment %d: ignore (addr %X) size %X", i, shdr->load_addr, shdr->data_len); - } - int l=(shdr->data_len+3)&(~3); - p+=l; - } - - ESP_LOGD(TAG, "Unmap"); - appfsBlMunmap(); - appfsBlMapRegions(file_handle, mapRegions, noMaps); - - ESP_LOGD(TAG, "Appfs MMU adjustments done. Starting app at 0x%08x", entry_addr); - typedef void (*entry_t)(void); - entry_t entry = ((entry_t) entry_addr); - (*entry)(); -} - - -//Before the app is started, the bootloader manually sets up the cache. We can't easily intercept -//that in order to do the transformation from fake partition offsets to appfs file contents, -//however the bootloader does have a call that it calls just before it starts up the app. We hook -//that here, manually set the cache regions to the actual app. -IRAM_ATTR void __wrap_bootloader_console_deinit() { - if (file_handle!=APPFS_INVALID_FD) { - mmap_and_start_app(); - } - //Actual partition selected. Simply call the actual function. - __real_bootloader_console_deinit(); -} - - -//These functions are used by appfs to access the flash: these should always use unwrapped calls. -IRAM_ATTR const void* appfs_bootloader_mmap(uint32_t src_addr, uint32_t size) { - return __real_bootloader_mmap(src_addr, size); -} - -IRAM_ATTR void appfs_bootloader_munmap(const void *mapping) { - return __real_bootloader_munmap(mapping); -} - -IRAM_ATTR esp_err_t appfs_bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt) { - return __real_bootloader_flash_read(src_addr, dest, size, allow_decrypt); -} - - -#endif diff --git a/bootloader_components/main/appfs_flashfunctions_wrapper.h b/bootloader_components/main/appfs_flashfunctions_wrapper.h deleted file mode 100644 index fd7566b..0000000 --- a/bootloader_components/main/appfs_flashfunctions_wrapper.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#ifdef BOOTLOADER_BUILD - -/* -The appfs wrapper layer wraps (using thr gcc linker wrapping function, see the CMakeFiles.txt -file in this directory) the calls that the rest of the bootloader uses, and maps accesses to -the appfs partition to transparently map to access to the selected appfs file instead. -*/ - -//Initialize the wrapper. Handle is a handle to the appfs file, part_start and part_size -//must refer to the offset and the size of the appfs partition. -void appfs_wrapper_init(appfs_handle_t handle, size_t part_start, size_t part_size); - -//Un-initialize the wrapper. Flash access will always access raw flash after this. -void appfs_wrapper_deinit(); - -#endif diff --git a/bootloader_components/main/bootloader_start.c b/bootloader_components/main/bootloader_start.c deleted file mode 100644 index 2900266..0000000 --- a/bootloader_components/main/bootloader_start.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifdef BOOTLOADER_BUILD - -#include -#include "sdkconfig.h" -#include "esp_log.h" -#include "bootloader_init.h" -#include "bootloader_utility.h" -#include "bootloader_common.h" -#include "appfs.h" -#include "bootloader_flash_priv.h" -#include "appfs_flashfunctions_wrapper.h" - -static const char *TAG="bootloader"; - -//Copied from kchal, which we don't want to link inhere. -//See 8bkc-hal/kchal.c for explanation of the bits in the store0 register -static int appfs_get_new_app() { - uint32_t r=REG_READ(RTC_CNTL_STORE0_REG); - ESP_LOGI(TAG, "RTC store0 reg: %x", r); - if ((r&0xFF000000)!=0xA5000000) return -1; - return r&0xff; -} - -//Find the position/size of the appfs partition -static bool find_appfs_part(size_t *pos, size_t *len) { - const esp_partition_info_t *partitions = bootloader_mmap(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN); - if (!partitions) { - ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN); - return false; - } - ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions); - - int num_partitions; - esp_err_t err = esp_partition_table_verify(partitions, true, &num_partitions); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to verify partition table"); - return false; - } - - bool found=false; - for (int i = 0; i < num_partitions; i++) { - const esp_partition_info_t *partition = &partitions[i]; - if (partition->type==APPFS_PART_TYPE && partition->subtype==APPFS_PART_SUBTYPE) { - *pos=partition->pos.offset; - *len=partition->pos.size; - found=true; - } - } - - bootloader_munmap(partitions); - return found; -} - - - -/* - * We arrive here after the ROM bootloader finished loading this second stage bootloader from flash. - * The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset. - * We do have a stack, so we can do the initialization in C. - */ -void __attribute__((noreturn)) call_start_cpu0(void) -{ - // Hardware initialization - if (bootloader_init() != ESP_OK) { - bootloader_reset(); - } - - bootloader_state_t bs = {0}; - if (!bootloader_utility_load_partition_table(&bs)) { - ESP_LOGE(TAG, "load partition table error!"); - bootloader_reset(); - } - - size_t appfs_pos, appfs_len; - if (!find_appfs_part(&appfs_pos, &appfs_len)) { - ESP_LOGE(TAG, "No appfs found!"); - goto error; - } - - //We have an appfs - ESP_LOGI(TAG, "AppFs found @ offset 0x%X", appfs_pos); - esp_err_t err=appfsBlInit(appfs_pos, appfs_len); - if (err != ESP_OK) { - ESP_LOGE(TAG, "AppFs initialization failed"); - appfsBlDeinit(); - goto error; - } - ESP_LOGI(TAG, "AppFs initialized"); - - int app=appfs_get_new_app(); - appfs_handle_t handle=0; - if (app<0) { - //Load default app - handle=appfsOpen("chooser.app"); - } else { - handle=app; - } - if (handle==APPFS_INVALID_FD) { - ESP_LOGE(TAG, "Couldn't open app (%d)!", app); - appfsBlDeinit(); - goto error; - } - - ESP_LOGI(TAG, "Wrapping flash functions and booting app..."); - appfs_wrapper_init(handle, appfs_pos, appfs_len); - //De-init the high-level parts of appfs. Reading/mmap'ping a file handle still is explicitly - //allowed after this, though. - appfsBlDeinit(); - //Note that the rest of the bootloader code has no clue about appfs, and as such won't try - //to boot it. We 'fix' that by chucking the appfs partition (which is now wrapped so the rest - //of the bootloader reads from the selected file when it thinks it loads from the app) into - //the top OTA slot. - bs.ota[0].offset=appfs_pos; - bs.ota[0].size=appfs_len; - bs.app_count=1; - //And bingo bango, we can now boot from appfs as if it is the first ota partition. - bootloader_utility_load_boot_image(&bs, 0); - //Still here? Must be an error. -error: - //Try to fallback to factory part - bootloader_utility_load_boot_image(&bs, -1); - - ESP_LOGE(TAG, "Bootloader end"); - bootloader_reset(); -} - - - -// Return global reent struct if any newlib functions are linked to bootloader -struct _reent *__getreent(void) -{ - return _GLOBAL_REENT; -} - -#endif diff --git a/components/appfs b/components/appfs new file mode 160000 index 0000000..6a1563b --- /dev/null +++ b/components/appfs @@ -0,0 +1 @@ +Subproject commit 6a1563b35f38b426a13d616ab45a1feeee366b43 diff --git a/components/appfs/CMakeLists.txt b/components/appfs/CMakeLists.txt deleted file mode 100644 index 75c6ecd..0000000 --- a/components/appfs/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ - -idf_component_register(SRC_DIRS . - REQUIRES log spi_flash bootloader_support - INCLUDE_DIRS . ) - -target_compile_options(${COMPONENT_LIB} PRIVATE -DPROJECT_NAME="${CMAKE_PROJECT_NAME}") diff --git a/components/appfs/appfs.c b/components/appfs/appfs.c deleted file mode 100644 index bf65984..0000000 --- a/components/appfs/appfs.c +++ /dev/null @@ -1,816 +0,0 @@ -/* -Theory of operation: -An appfs filesystem is meant to store executable applications (=ESP32 programs) alongside other -data that is mmap()-able as a contiguous file. - -Appfs does that by making sure the files rigidly adhere to the 64K-page-structure (called a 'sector' -in this description) as predicated by the ESP32s MMU. This way, every file can be mmap()'ed into a -contiguous region or ran as an ESP32 application. (For the future, maybe: Smaller files can be stored -in parts of a 64K page, as long as all are contiguous and none cross any 64K boundaries. -What about fragmentation tho?) - -Because of these reasons, only a few operations are available: -- Creating a file. This needs the filesize to be known beforehand; a file cannot change size afterwards. -- Modifying a file. This follows the same rules as spi_flash_* because it maps directly to the underlying flash. -- Deleting a file -- Mmap()ping a file -This makes the interface to appfs more akin to the partition interface than to a real filesystem. - -At the moment, appfs is not yet tested with encrypted flash; compatibility is unknown. - -Filesystem meta-info is stored using the first sector: there are 2 32K half-sectors there with management -info. Each has a serial and a checksum. The sector with the highest serial and a matching checksum is -taken as current; the data will ping-pong between the sectors. (And yes, this means the pages in these -sectors will be rewritten every time a file is added/removed. Appfs is built with the assumption that -it's a mostly store-only filesystem and apps will only change every now and then. The flash chips -connected to the ESP32 chips usually can do up to 100.000 erases, so for most purposes the lifetime of -the flash with appfs on it exceeds the lifetime of the product.) - -Appfs assumes a partition of 16MiB or less, allowing for 256 128-byte sector descriptors to be stored in -the management half-sectors. The first descriptor is a header used for filesystem meta-info. - -Metainfo is stored per sector; each sector descriptor contains a zero-terminated filename (no -directories are supported, but '/' is an usable character), the size of the file and a pointer to the -next entry for the file if needed. The filename is only set for the first sector; it is all zeroes -(actually: ignored) for other entries. - -Integrity of the meta-info is guaranteed: the file system will never be in a state where sectors are -lost or anything. Integrity of data is *NOT* guaranteed: on power loss, data may be half-written, -contain sectors with only 0xff, and so on. It's up to the user to take care of this. However, files that -are not written to do not run the risk of getting corrupted. - -With regards to this code: it is assumed that an ESP32 will only have one appfs on flash, so everything -is implemented as a singleton. - -*/ - -#include -#include -#include -#include -#include -#include -#include "esp_spi_flash.h" -#include "esp_partition.h" -#include "esp_log.h" -#include "esp_err.h" -#include "appfs.h" -#include "rom/cache.h" -#include "sdkconfig.h" - - -#if !CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED -#error "Appfs will not work with SPI flash dangerous regions checking. Please use 'make menuconfig' to enable writing to dangerous regions." -#endif - -static const char *TAG = "appfs"; - - -#define APPFS_SECTOR_SZ SPI_FLASH_MMU_PAGE_SIZE -#define APPFS_META_SZ (APPFS_SECTOR_SZ/2) -#define APPFS_META_CNT 2 -#define APPFS_META_DESC_SZ 128 -#define APPFS_PAGES 255 -#define APPFS_MAGIC "AppFsDsc" - -#define APPFS_USE_FREE 0xff //No file allocated here -#define APPFS_ILLEGAL 0x55 //Sector cannot be used (usually because it's outside the partition) -#define APPFS_USE_DATA 0 //Sector is in use for data - -typedef struct __attribute__ ((__packed__)) { - uint8_t magic[8]; //must be AppFsDsc - uint32_t serial; - uint32_t crc32; - uint8_t reserved[128-16]; -} AppfsHeader; - -typedef struct __attribute__ ((__packed__)) { - char name[112]; //Only set for 1st sector of file. Rest has name set to 0xFF 0xFF ... - uint32_t size; //in bytes - uint8_t next; //next page containing the next 64K of the file; 0 if no next page (Because allocation always starts at 0 and pages can't refer to a lower page, 0 can never occur normally) - uint8_t used; //one of APPFS_USE_* - uint8_t reserved[10]; -} AppfsPageInfo; - -typedef struct __attribute__ ((__packed__)) { - AppfsHeader hdr; - AppfsPageInfo page[APPFS_PAGES]; -} AppfsMeta; - -static int appfsActiveMeta=0; //number of currently active metadata half-sector (0 or 1) -static const AppfsMeta *appfsMeta=NULL; //mmap'ed flash -#ifndef BOOTLOADER_BUILD -static const esp_partition_t *appfsPart=NULL; -static spi_flash_mmap_handle_t appfsMetaMmapHandle; -#else -static uint32_t appfsPartOffset=0; -#endif - - -static int page_in_part(int page) { -#ifndef BOOTLOADER_BUILD - return ((page+1)*APPFS_SECTOR_SZ < appfsPart->size); -#else - return 1; -#endif -} - -//Find active meta half-sector. Updates appfsActiveMeta to the most current one and returns ESP_OK success. -//Returns ESP_ERR_NOT_FOUND when no active metasector is found. -static esp_err_t findActiveMeta() { - int validSec=0; //bitmap of valid sectors - uint32_t serial[APPFS_META_CNT]={0}; - AppfsHeader hdr; - for (int sec=0; secserial[best]) best=sec; - } - } - - ESP_LOGI(TAG, "Meta page 0: %svalid (serial %d)", (validSec&1)?"":"in", serial[0]); - ESP_LOGI(TAG, "Meta page 1: %svalid (serial %d)", (validSec&2)?"":"in", serial[1]); - - //'best' here is either still -1 (no valid sector found) or the sector with the highest valid serial. - if (best==-1) { - ESP_LOGI(TAG, "No valid page found."); - //Eek! Nothing found! - return ESP_ERR_NOT_FOUND; - } else { - ESP_LOGI(TAG, "Using page %d as current.", best); - } - appfsActiveMeta=best; - return ESP_OK; -} - -#ifdef BOOTLOADER_BUILD -IRAM_ATTR -#endif -static int appfsGetFirstPageFor(const char *filename) { - for (int j=0; j=APPFS_PAGES) return false; - if (appfsMeta[appfsActiveMeta].page[(int)fd].used!=APPFS_USE_DATA) return false; - if (appfsMeta[appfsActiveMeta].page[(int)fd].name[0]==0xff) return false; - return true; -} - -int appfsExists(const char *filename) { - return (appfsGetFirstPageFor(filename)==-1)?0:1; -} - -appfs_handle_t appfsOpen(const char *filename) { - return appfsGetFirstPageFor(filename); -} - -void appfsClose(appfs_handle_t handle) { - //Not needed in this implementation. Added for possible later use (concurrency?) -} - -void appfsEntryInfo(appfs_handle_t fd, const char **name, int *size) { - if (name) *name=appfsMeta[appfsActiveMeta].page[fd].name; - if (size) *size=appfsMeta[appfsActiveMeta].page[fd].size; -} - -appfs_handle_t appfsNextEntry(appfs_handle_t fd) { - if (fd==APPFS_INVALID_FD) { - fd=0; - } else { - fd++; - } - - if (fd>=APPFS_PAGES || fd<0) return APPFS_INVALID_FD; - - while (appfsMeta[appfsActiveMeta].page[fd].used!=APPFS_USE_DATA || appfsMeta[appfsActiveMeta].page[fd].name[0]==0xff) { - fd++; - if (fd>=APPFS_PAGES) return APPFS_INVALID_FD; - } - - return fd; -} - -size_t appfsGetFreeMem() { - size_t ret=0; - for (int i=0; ipage_count) return ESP_ERR_NO_MEM; - } - } - DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 ); - DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 ); - Cache_Read_Enable( 0 ); - return ESP_OK; -} - -IRAM_ATTR void* appfsBlMmap(int fd) { - if (appfsMeta) appfs_bootloader_munmap(appfsMeta); - appfsMeta=NULL; - //Bootloader_mmap only allows mapping of one consecutive memory range. We need more than that, so we essentially - //replicate the function here. - - Cache_Read_Disable(0); - Cache_Flush(0); - int page=fd; - for (int i=0; i<50; i++) { -// ESP_LOGI(TAG, "Mapping flash addr %X to mem addr %X for page %d", appfsPartOffset+((pages[i]+1)*APPFS_SECTOR_SZ), MMU_BLOCK0_VADDR+(i*APPFS_SECTOR_SZ), pages[i]); - int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR+(i*APPFS_SECTOR_SZ), - appfsPartOffset+((page+1)*APPFS_SECTOR_SZ), 64, 1); - if (e != 0) { - ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d", e); - Cache_Read_Enable(0); - return NULL; - } - page=next_page_for[page]; - if (page==0) break; - } - Cache_Read_Enable(0); - return (void *)(MMU_BLOCK0_VADDR); -} - -IRAM_ATTR void appfsBlMunmap() { - /* Full MMU reset */ - Cache_Read_Disable(0); - Cache_Flush(0); - mmu_init(0); - if (keep_meta_mapped) { - appfsMeta=appfs_bootloader_mmap(appfsPartOffset, APPFS_SECTOR_SZ); - } -} - -IRAM_ATTR esp_err_t appfs_bootloader_read(int fd, size_t src_addr, void *dest, size_t size) { - int page=fd; - int pos=0; - int have_read=0; - uint8_t *destp=(uint8_t*)dest; - int offset_in_page=src_addr&(APPFS_SECTOR_SZ-1); - for (int i=0; i<255; i++) { - if (pos+APPFS_SECTOR_SZ-1>=src_addr) { - size_t rsize=APPFS_SECTOR_SZ-offset_in_page; - if (rsize>size) rsize=size; - esp_err_t r=appfs_bootloader_flash_read(appfsPartOffset+((page+1)*APPFS_SECTOR_SZ)+offset_in_page, destp+have_read, rsize, true); - if (r!=ESP_OK) return r; - offset_in_page=0; - have_read+=rsize; - if (have_read>=size) { - return ESP_OK; - } - } - page=next_page_for[page]; - if (page==0) break; - pos+=APPFS_SECTOR_SZ; - } - return ESP_OK; -} - -#else //so if !BOOTLOADER_BUILD - -//Modifies the header in hdr to the correct crc and writes it to meta info no metano. -//Assumes the serial etc is in order already, and the header section for metano has been erased. -static esp_err_t writeHdr(AppfsHeader *hdr, int metaNo) { - hdr->crc32=0; - uint32_t crc=0; - crc=crc32_le(crc, (const uint8_t *)hdr, APPFS_META_DESC_SZ); - for (int j=0; jcrc32=crc; - return esp_partition_write(appfsPart, metaNo*APPFS_META_SZ, hdr, sizeof(AppfsHeader)); -} - -//Kill all existing filesystem metadata and re-initialize the fs. -static esp_err_t initializeFs() { - esp_err_t r; - //Kill management sector - r=esp_partition_erase_range(appfsPart, 0, APPFS_SECTOR_SZ); - if (r!=ESP_OK) return r; - //All the data pages are now set to 'free'. Add a header that makes the entire mess valid. - AppfsHeader hdr; - memset(&hdr, 0xff, sizeof(hdr)); - memcpy(hdr.magic, APPFS_MAGIC, 8); - hdr.serial=0; - //Mark pages outside of partition as invalid. - int lastPage=(appfsPart->size/APPFS_SECTOR_SZ); - for (int j=lastPage; j0) { - //Eek! Can't allocate enough space! - ESP_LOGD(TAG, "Not enough free space!"); - return ESP_ERR_NO_MEM; - } - - //Re-write a new meta page but with file allocated - int newMeta=(appfsActiveMeta+1)%APPFS_META_CNT; - ESP_LOGD(TAG, "Re-writing meta data to meta page %d...", newMeta); - r=esp_partition_erase_range(appfsPart, newMeta*APPFS_META_SZ, APPFS_META_SZ); - if (r!=ESP_OK) return r; - //Prepare header - AppfsHeader hdr; - memcpy(&hdr, &appfsMeta[appfsActiveMeta].hdr, sizeof(hdr)); - hdr.serial++; - hdr.crc32=0; - for (int j=0; jaddress/SPI_FLASH_MMU_PAGE_SIZE)+1; - while (offset >= APPFS_SECTOR_SZ) { - page=appfsMeta[appfsActiveMeta].page[page].next; - offset-=APPFS_SECTOR_SZ; - ESP_LOGD(TAG, "Skipping a page (to page %d), remaining offset 0x%X", page, offset); - } - - int *pages=alloca(sizeof(int)*((len/APPFS_SECTOR_SZ)+1)); - int nopages=0; - size_t mappedlen=0; - while(len>mappedlen) { - pages[nopages++]=page+dataStartPage; - ESP_LOGD(TAG, "Mapping page %d (part offset %d).", page, dataStartPage); - page=appfsMeta[appfsActiveMeta].page[page].next; - mappedlen+=APPFS_SECTOR_SZ; - } - - r=spi_flash_mmap_pages(pages, nopages, memory, out_ptr, out_handle); - if (r!=ESP_OK) { - ESP_LOGD(TAG, "Can't map file: pi_flash_mmap_pages returned %d\n", r); - return r; - } - *out_ptr=((uint8_t*)*out_ptr)+offset; - return ESP_OK; -} - -void appfsMunmap(spi_flash_mmap_handle_t handle) { - spi_flash_munmap(handle); -} - -//Just mmaps and memcpys the data. Maybe not the fastest ever, but hey, if you want that you should mmap -//and read from the flash cache memory area yourself. -esp_err_t appfsRead(appfs_handle_t fd, size_t start, void *buf, size_t len) { - const void *flash; - spi_flash_mmap_handle_t handle; - esp_err_t r=appfsMmap(fd, start, len, &flash, SPI_FLASH_MMAP_DATA, &handle); - if (r!=ESP_OK) return r; - memcpy(buf, flash, len); - spi_flash_munmap(handle); - return ESP_OK; -} - - -esp_err_t appfsErase(appfs_handle_t fd, size_t start, size_t len) { - esp_err_t r; - int page=(int)fd; - if (!appfsFdValid(page)) return ESP_ERR_NOT_FOUND; - //Bail out if trying to erase past the file end. - //Allow erases past the end of the file but still within the page reserved for the file. - int roundedSize=(appfsMeta[appfsActiveMeta].page[page].size+(APPFS_SECTOR_SZ-1))&(~(APPFS_SECTOR_SZ-1)); - if (roundedSize < (start+len)) { - return ESP_ERR_INVALID_SIZE; - } - - //Find initial page - while (start >= APPFS_SECTOR_SZ) { - page=appfsMeta[appfsActiveMeta].page[page].next; - start-=APPFS_SECTOR_SZ; - } - //Page now is the initial page. Start is the offset into the page we need to start at. - - while (len>0) { - size_t size=len; - //Make sure we do not go over a page boundary - if ((size+start)>APPFS_SECTOR_SZ) size=APPFS_SECTOR_SZ-start; - ESP_LOGD(TAG, "Erasing page %d offset 0x%X size 0x%X", page, start, size); - r=esp_partition_erase_range(appfsPart, (page+1)*APPFS_SECTOR_SZ+start, size); - if (r!=ESP_OK) return r; - page=appfsMeta[appfsActiveMeta].page[page].next; - len-=size; - start=0; //offset is not needed anymore - } - return ESP_OK; -} - -esp_err_t appfsWrite(appfs_handle_t fd, size_t start, uint8_t *buf, size_t len) { - esp_err_t r; - int page=(int)fd; - if (!appfsFdValid(page)) return ESP_ERR_NOT_FOUND; - if (appfsMeta[appfsActiveMeta].page[page].size < (start+len)) { - return ESP_ERR_INVALID_SIZE; - } - - while (start > APPFS_SECTOR_SZ) { - page=appfsMeta[appfsActiveMeta].page[page].next; - start-=APPFS_SECTOR_SZ; - } - while (len>0) { - size_t size=len; - if (size+start>APPFS_SECTOR_SZ) size=APPFS_SECTOR_SZ-start; - ESP_LOGD(TAG, "Writing to page %d offset %d size %d", page, start, size); - r=esp_partition_write(appfsPart, (page+1)*APPFS_SECTOR_SZ+start, buf, size); - if (r!=ESP_OK) return r; - page=appfsMeta[appfsActiveMeta].page[page].next; - len-=size; - buf+=size; - start=0; - } - return ESP_OK; -} - -void appfsDump() { - printf("AppFsDump: ..=free XX=illegal no=next page\n"); - for (int i=0; i<16; i++) printf("%02X-", i); - printf("\n"); - for (int i=0; iaddress; - - int page=(phys_offs/APPFS_SECTOR_SZ)-1; - if (page<0 || page>=APPFS_PAGES) { - return ESP_ERR_NOT_FOUND; - } - - //Find first sector for this page. - int tries=APPFS_PAGES; //make sure this loop always exits - while (appfsMeta[appfsActiveMeta].page[page].name[0]==0xff) { - int i; - for (i=0; i=APPFS_PAGES) return ESP_ERR_NOT_FOUND; - tries--; - } - - //Okay, found! - *ret_app=page; - return ESP_OK; -} - - - -#endif diff --git a/components/appfs/appfs.h b/components/appfs/appfs.h deleted file mode 100644 index ee29268..0000000 --- a/components/appfs/appfs.h +++ /dev/null @@ -1,297 +0,0 @@ -#ifndef APPFS_H -#define APPFS_H - -#include "esp_err.h" -#include -#include "esp_spi_flash.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define APPFS_PART_TYPE 0x43 /*