From 11db1b0daf3beb6d19eb1db6b7a22b2859b73f36 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 9 Nov 2018 19:54:17 +0800 Subject: [PATCH] feat(bootloader): Support v2 firmware updates to v3 by OTA --- components/app_update/esp_ota_ops.c | 6 - .../subproject/main/bootloader_start.c | 13 + .../subproject/main/esp8266.bootloader.ld | 4 +- .../subproject/main/esp8266.bootloader.rom.ld | 2 + .../bootloader_support/src/bootloader_init.c | 2 + .../src/bootloader_utility.c | 15 + components/esp8266/Kconfig | 22 + components/esp8266/Makefile.projbuild | 29 +- .../esp8266/include/esp8266/eagle_soc.h | 6 + .../esp8266/include/esp8266/rom_functions.h | 4 + .../esp8266/include/esp8266/spi_register.h | 8 + components/esp8266/source/task_wdt.c | 5 - components/spi_flash/component.mk | 7 + components/spi_flash/include/spi_flash.h | 46 +++ components/spi_flash/port/port.c | 385 ++++++++++++++++++ components/spi_flash/src/spi_flash.c | 26 ++ .../partitions_two_ota_v2tov3.1MB.csv | 11 + tools/pack_fw.py | 176 ++++++++ 18 files changed, 752 insertions(+), 15 deletions(-) create mode 100644 components/spi_flash/port/port.c create mode 100644 examples/system/universal_ota/partitions_two_ota_v2tov3.1MB.csv create mode 100644 tools/pack_fw.py diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 7dfc4c068..9f41cda7d 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -539,13 +539,10 @@ const esp_partition_t* esp_ota_get_running_partition(void) /* Find the flash address of this exact function. By definition that is part of the currently running firmware. Then find the enclosing partition. */ -#ifdef CONFIG_TARGET_PLATFORM_ESP32 size_t phys_offs = spi_flash_cache2phys(esp_ota_get_running_partition); assert (phys_offs != SPI_FLASH_CACHE2PHYS_FAIL); /* indicates cache2phys lookup is buggy */ -#endif -#if CONFIG_TARGET_PLATFORM_ESP32 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL); @@ -561,9 +558,6 @@ const esp_partition_t* esp_ota_get_running_partition(void) } abort(); /* Partition table is invalid or corrupt */ -#else - return esp_ota_get_boot_partition(); -#endif } diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index b748d7fcb..0bf6afa0a 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -21,6 +21,7 @@ #include "bootloader_common.h" #include "esp_image_format.h" #include "esp_log.h" +#include "esp_spi_flash.h" static const char* TAG = "boot"; @@ -112,6 +113,18 @@ static int selected_boot_partition(const bootloader_state_t *bs) } #endif } +#endif +#ifdef CONFIG_ESP8266_BOOT_COPY_APP + if (boot_index == 1) { + ESP_LOGI(TAG, "Copy application from OAT1 to OTA0, please wait ..."); + int ret = esp_patition_copy_ota1_to_ota0(bs); + if (ret) { + ESP_LOGE(TAG, "Fail to initialize OTA0"); + return INVALID_INDEX; + } + + boot_index = 0; + } #endif // Customer implementation. // if (gpio_pin_1 == true && ...){ diff --git a/components/bootloader/subproject/main/esp8266.bootloader.ld b/components/bootloader/subproject/main/esp8266.bootloader.ld index 122dfd332..72c5c29a2 100644 --- a/components/bootloader/subproject/main/esp8266.bootloader.ld +++ b/components/bootloader/subproject/main/esp8266.bootloader.ld @@ -12,8 +12,8 @@ MEMORY { dport0_seg : org = 0x3FF00000, len = 0x10 - /* All .data/.bss/heap are in this segment. */ - dram_seg : org = 0x3FFE8000, len = 0x18000 + /* All .data/.bss/heap are in this segment. Reserve 1KB for old boot or ROM boot */ + dram_seg : org = 0x3FFE8000, len = 0x18000 - 0x400 /* Functions which are critical should be put in this segment. */ iram_seg : org = 0x40100000, len = 0x8000 diff --git a/components/bootloader/subproject/main/esp8266.bootloader.rom.ld b/components/bootloader/subproject/main/esp8266.bootloader.rom.ld index 7f4e15cd4..3ff8f2710 100644 --- a/components/bootloader/subproject/main/esp8266.bootloader.rom.ld +++ b/components/bootloader/subproject/main/esp8266.bootloader.rom.ld @@ -1,6 +1,8 @@ PROVIDE ( ets_memcpy = 0x400018b4 ); PROVIDE ( SPIRead = 0x40004b1c ); +PROVIDE ( SPIWrite = 0x40004a4c ); +PROVIDE ( SPIEraseSector = 0x40004a00 ); PROVIDE ( gpio_input_get = 0x40004cf0 ); diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index adaa0af09..2ecf0a581 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -648,6 +648,8 @@ static void update_flash_config(const esp_image_header_t* pfhdr) ESP_LOGD(TAG, "bootloader initialize SPI flash clock and I/O"); #endif /* CONFIG_BOOTLOADER_INIT_SPI_FLASH */ + + Cache_Read_Disable(); } static void print_flash_info(const esp_image_header_t* phdr) diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index b7e828838..c6855c1a1 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -512,6 +512,13 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs) esp_err_t err; int num_partitions; +#ifdef CONFIG_ESP8266_OTA_FROM_OLD + if (esp_patition_table_init_location()) { + ESP_LOGE(TAG, "Failed to update partition table location"); + return false; + } +#endif + #ifdef CONFIG_SECURE_BOOT_ENABLED if(esp_secure_boot_enabled()) { ESP_LOGI(TAG, "Verifying partition table signature..."); @@ -605,6 +612,14 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs) bootloader_munmap(partitions); +#ifdef CONFIG_ESP8266_OTA_FROM_OLD + ESP_LOGI(TAG, "Copy firmware ..."); + if (esp_patition_table_init_data(bs)) { + ESP_LOGE(TAG,"Failed to update partition data"); + return false; + } +#endif + ESP_LOGI(TAG,"End of partition table"); return true; } diff --git a/components/esp8266/Kconfig b/components/esp8266/Kconfig index a48313d86..1427e193d 100644 --- a/components/esp8266/Kconfig +++ b/components/esp8266/Kconfig @@ -213,6 +213,28 @@ config CRYSTAL_USED_40MHZ bool "40MHz" endchoice +config ESP8266_OTA_FROM_OLD + bool "(**Expected**)ESP8266 update from old SDK by OTA" + default n + depends on TARGET_PLATFORM_ESP8266 + select ESP8266_BOOT_COPY_APP + help + The function is not released. + + Enable this option, script will generate the complete firmware for both old RTOS SDK(before V3.0) + and NonOS SDK to update to v3 by OTA. + + The old RTOS SDK(before V3.0) or NonOS SDK can download the firmware to its partition and run it as it self's application. + +config ESP8266_BOOT_COPY_APP + bool "(**Expected**)Boot copy app" + default n + help + The function is not released. + + Enable this option, when it is that "OTA1" application is to run after update by OTA, + bootloader will copy "OTA1" application to "OTA0" partition and run "OTA0". + endmenu menu WIFI diff --git a/components/esp8266/Makefile.projbuild b/components/esp8266/Makefile.projbuild index 63bcfee25..735d0ae94 100644 --- a/components/esp8266/Makefile.projbuild +++ b/components/esp8266/Makefile.projbuild @@ -89,10 +89,22 @@ OTA_BIN := ./build/$(PROJECT_NAME).ota.bin OTA1_BIN := ./build/$(PROJECT_NAME).app1.bin OTA2_BIN := ./build/$(PROJECT_NAME).app2.bin +OTA_V2_TO_V3_BIN := ./build/$(PROJECT_NAME).v2_to_v3.ota.bin + +CONFIG_APP2_OFFSET ?= $(CONFIG_APP1_OFFSET) +CONFIG_APP2_SIZE ?= $(CONFIG_APP1_SIZE) + +OTA1_OFFSET := CONFIG_APP1_OFFSET +ifdef CONFIG_ESP8266_BOOT_COPY_APP +OTA2_LINK_OFFSET := $(CONFIG_APP1_OFFSET) +else +OTA2_LINK_OFFSET := $(CONFIG_APP2_OFFSET) +endif + $(OTA2_BIN): all_binaries ifeq ($(CONFIG_ESPTOOLPY_FLASHSIZE), "1MB") @rm -f ./build/esp8266/esp8266_out.ld - @make APP_OFFSET=$(CONFIG_APP2_OFFSET) APP_SIZE=$(CONFIG_APP2_SIZE) CFLAGS= CXXFLAGS= + @make APP_OFFSET=$(OTA2_LINK_OFFSET) APP_SIZE=$(CONFIG_APP2_SIZE) CFLAGS= CXXFLAGS= endif @cp $(RAW_BIN) $(OTA2_BIN) @echo [GEN] $(OTA2_BIN) @@ -113,9 +125,22 @@ endif @cp $(OTA1_BIN) $(RAW_BIN) @echo [GEN] $(OTA_BIN) +ifdef CONFIG_ESP8266_OTA_FROM_OLD +$(OTA_V2_TO_V3_BIN): $(OTA_BIN) + @cp $(RAW_BIN) $(RAW_BIN).tmp.bak + @cp $(OTA1_BIN) $(RAW_BIN) + @python $(IDF_PATH)/tools/pack_fw.py --output $(OTA_V2_TO_V3_BIN) pack3 $(ESPTOOL_ALL_FLASH_ARGS) + @cp $(RAW_BIN).tmp.bak $(RAW_BIN) + @echo [GEN] $(OTA_V2_TO_V3_BIN) +endif + +ifdef CONFIG_ESP8266_OTA_FROM_OLD +ota: $(OTA_V2_TO_V3_BIN) +else ota: $(OTA_BIN) +endif ota-clean: - @rm -f $(OTA_BIN) $(OTA1_BIN) $(OTA2_BIN) + @rm -f $(OTA_BIN) $(OTA1_BIN) $(OTA2_BIN) $(OTA_V2_TO_V3_BIN) clean: ota-clean diff --git a/components/esp8266/include/esp8266/eagle_soc.h b/components/esp8266/include/esp8266/eagle_soc.h index 28d105a80..ec5318a9b 100644 --- a/components/esp8266/include/esp8266/eagle_soc.h +++ b/components/esp8266/include/esp8266/eagle_soc.h @@ -140,6 +140,12 @@ #define WDT_CTL_EN_LSB 0 #define WDT_FEED_VALUE 0x73 + +#define WDT_REG_READ(_reg) REG_READ(PERIPHS_WDT_BASEADDR + _reg) +#define WDT_REG_WRITE(_reg, _val) REG_WRITE(PERIPHS_WDT_BASEADDR + _reg, _val) +#define CLEAR_WDT_REG_MASK(_reg, _mask) WDT_REG_WRITE(_reg, WDT_REG_READ(_reg) & (~_mask)) +#define WDT_FEED() WDT_REG_WRITE(WDT_RST_ADDRESS, WDT_FEED_VALUE) + //}} //RTC reg {{ diff --git a/components/esp8266/include/esp8266/rom_functions.h b/components/esp8266/include/esp8266/rom_functions.h index 2eec98748..80d8a593d 100644 --- a/components/esp8266/include/esp8266/rom_functions.h +++ b/components/esp8266/include/esp8266/rom_functions.h @@ -33,6 +33,10 @@ int SPI_write_status(esp_spi_flash_chip_t *chip, uint32_t status); int SPI_read_status(esp_spi_flash_chip_t *chip, uint32_t *status); int Enable_QMode(esp_spi_flash_chip_t *chip); +int SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size); +int SPIRead(uint32_t addr, void *dst, uint32_t size); +int SPIEraseSector(uint32_t sector_num); + void Cache_Read_Disable(); void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v); diff --git a/components/esp8266/include/esp8266/spi_register.h b/components/esp8266/include/esp8266/spi_register.h index 17c9dcca0..1bf5eeb3b 100644 --- a/components/esp8266/include/esp8266/spi_register.h +++ b/components/esp8266/include/esp8266/spi_register.h @@ -263,6 +263,14 @@ extern "C" { #define PERIPHS_SPI_FLASH_USRREG (0x60000200 + 0x1c) +#define CACHE_MAP_1M_HIGH BIT25 +#define CACHE_MAP_2M BIT24 +#define CACHE_MAP_SEGMENT_S 16 +#define CACHE_MAP_SEGMENT_MASK 0x3 +#define CACHE_BASE_ADDR 0x40200000 +#define CACHE_2M_SIZE 0x00200000 +#define CACHE_1M_SIZE 0x00100000 + #ifdef __cplusplus } #endif diff --git a/components/esp8266/source/task_wdt.c b/components/esp8266/source/task_wdt.c index 0c8116f8f..40cd8c307 100644 --- a/components/esp8266/source/task_wdt.c +++ b/components/esp8266/source/task_wdt.c @@ -21,11 +21,6 @@ #include "portmacro.h" #include "esp8266/eagle_soc.h" -#define WDT_REG_READ(_reg) REG_READ(PERIPHS_WDT_BASEADDR + _reg) -#define WDT_REG_WRITE(_reg, _val) REG_WRITE(PERIPHS_WDT_BASEADDR + _reg, _val) -#define CLEAR_WDT_REG_MASK(_reg, _mask) WDT_REG_WRITE(_reg, WDT_REG_READ(_reg) & (~_mask)) -#define WDT_FEED() WDT_REG_WRITE(WDT_RST_ADDRESS, WDT_FEED_VALUE) - static const char *TAG = "wdt"; #ifdef CONFIG_TASK_WDT_PANIC diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index 3172f3eb3..b9bbbd330 100644 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -9,3 +9,10 @@ COMPONENT_OBJS := src/spi_flash.o src/spi_flash_raw.o endif CFLAGS += -DPARTITION_QUEUE_HEADER=\"sys/queue.h\" + +ifdef CONFIG_ESP8266_OTA_FROM_OLD +ifdef IS_BOOTLOADER_BUILD +COMPONENT_SRCDIRS += port +COMPONENT_OBJS += port/port.o +endif +endif diff --git a/components/spi_flash/include/spi_flash.h b/components/spi_flash/include/spi_flash.h index 28ae64c03..b7dc6fc8b 100644 --- a/components/spi_flash/include/spi_flash.h +++ b/components/spi_flash/include/spi_flash.h @@ -32,6 +32,8 @@ extern "C" { #define SPI_READ_BUF_MAX 64 +#define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /* +#include +#include "esp_flash_data_types.h" +#include "esp_spi_flash.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "bootloader_config.h" +#include "esp_libc.h" +#include "esp8266/rom_functions.h" +#include "esp8266/eagle_soc.h" + +#define PARTITION_DATA_OFFSET (CONFIG_SPI_FLASH_SIZE / 2) + +typedef struct s_sys_param { + uint8_t flag; + uint8_t reserved1[3]; + uint32_t reserved2[7]; +} sys_param_t; + +typedef union s_boot_param { + struct { + uint8_t usr_bin : 4; + uint8_t flag : 4; + } boot_1; + + struct { + uint8_t usr_bin : 4; + uint8_t flag : 4; + uint8_t version; + } boot_2; + + struct { + uint8_t usr_bin : 2; + uint8_t boot_statue : 1; + uint8_t to_qio : 1; + uint8_t reserved1 : 4; + + uint8_t version : 5; + uint8_t test_pass_flag : 1; + uint8_t test_start_flag : 1; + uint8_t enhance_boot_flag : 1; + } boot_base; + + uint8_t data[4096]; +} boot_param_t; + +static const char *TAG = "partition_port"; +static uint32_t s_partition_offset; +static uint8_t s_cache_buf[SPI_FLASH_SEC_SIZE]; +static sys_param_t s_sys_param; +static boot_param_t s_boot_param; +static esp_spi_flash_chip_t s_flash_chip = { + 0x1640ef, + CONFIG_SPI_FLASH_SIZE, + 64 * 1024, + 4 * 1024, + 256, + 0xffff +}; + +static inline void esp_hw_reset(void) +{ + CLEAR_WDT_REG_MASK(WDT_CTL_ADDRESS, BIT0); + + WDT_REG_WRITE(WDT_OP_ADDRESS, 8); + WDT_REG_WRITE(WDT_OP_ND_ADDRESS, 8); + + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_RSTLEN_MASK, 7 << WDT_CTL_RSTLEN_LSB, 0); + // interrupt then reset + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_RSPMOD_MASK, 0 << WDT_CTL_RSPMOD_LSB, 0); + // start task watch dog1 + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 1 << WDT_CTL_EN_LSB, 0); + + while (1); +} + +static inline int spi_flash_read_data(uint32_t addr, void *buf, size_t n) +{ + int ret; + + ESP_LOGD(TAG, "read buffer %p total %d from 0x%x", buf, n ,addr); + + ret = SPI_read_data(&s_flash_chip, addr, buf, n); + + return ret; +} + +static inline int spi_flash_write_data(uint32_t addr, const void *buf, uint32_t n) +{ + int ret; + + ESP_LOGD(TAG, "write buffer %p total %d to 0x%x", buf, n ,addr); + + ret = SPIWrite(addr, (void *)buf, n); + + return ret; +} + +static inline int spi_flash_erase(uint32_t addr) +{ + int ret; + + ESP_LOGD(TAG, "erase addr is 0x%x", addr); + + ret = SPIEraseSector(addr / SPI_FLASH_SEC_SIZE); + + return ret; +} + +static inline uint32_t esp_get_updated_partition_table_addr(void) +{ + int ret; + size_t offset; + uint8_t user_bin; + const uint32_t sect = CONFIG_SPI_FLASH_SIZE / SPI_FLASH_SEC_SIZE - 3; + + if (s_partition_offset) + return s_partition_offset; + + ret = spi_flash_read_data((sect + 2) * SPI_FLASH_SEC_SIZE, &s_sys_param, sizeof(sys_param_t)); + if (ret) { + ESP_LOGE(TAG, "read V2 system param error %d", ret); + return -1UL; + } + + ESP_LOGD(TAG, "V2 system flag is %x", s_sys_param.flag); + + offset = s_sys_param.flag ? 1 : 0; + + ret = spi_flash_read_data((sect + offset) * SPI_FLASH_SEC_SIZE, &s_boot_param, sizeof(boot_param_t)); + if (ret) { + ESP_LOGE(TAG, "read V2 boot param error %d", ret); + return -1UL; + } + + if (s_boot_param.boot_base.usr_bin == 1) { + if (s_boot_param.boot_base.boot_statue == 1) + user_bin = 1; + else + user_bin = 0; + } else { + if (s_boot_param.boot_base.boot_statue == 1) + user_bin = 0; + else { + if (s_boot_param.boot_base.version == 4) + user_bin = 0; + else + user_bin = 1; + } + } + + if (user_bin) + s_partition_offset = CONFIG_PARTITION_TABLE_OFFSET + PARTITION_DATA_OFFSET; + else + s_partition_offset = CONFIG_PARTITION_TABLE_OFFSET; + + + ESP_LOGD(TAG, "Boot info %x %x %x %x %x", s_boot_param.boot_base.usr_bin, s_boot_param.boot_base.boot_statue, + s_boot_param.boot_base.version, user_bin, s_partition_offset); + + return s_partition_offset; +} + +static inline int spi_flash_write_data_safe(uint32_t addr, const void *buf, size_t n) +{ + int ret; + static uint8_t check_buf[SPI_FLASH_SEC_SIZE]; + + ret = spi_flash_erase(addr); + if (ret) { + ESP_LOGE(TAG, "erase flash 0x%x error", addr); + return -1; + } + + ret = spi_flash_write_data(addr, buf, n); + if (ret) { + ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", n, addr); + return 0; + } + + ret = spi_flash_read_data(addr, check_buf, n); + if (ret) { + ESP_LOGE(TAG, "read flash %d bytes from 0x%x error", n, addr); + return -1; + } + + if (memcmp(buf, check_buf, n)) { + ESP_LOGE(TAG, "check write flash %d bytes to 0x%x error", n, addr); + return -1; + } + + return 0; +} + +static int esp_flash_sector_copy(uint32_t dest, uint32_t src, uint32_t total_size) +{ + ESP_LOGD(TAG, "Start to copy data from 0x%x to 0x%x total %d", src, dest, total_size); + + for (uint32_t offset = 0; offset < total_size; offset += SPI_FLASH_SEC_SIZE) { + int ret; + + ret = spi_flash_read_data(src + offset, s_cache_buf, SPI_FLASH_SEC_SIZE); + if (ret) { + ESP_LOGE(TAG, "read flash %d bytes from 0x%x error", SPI_FLASH_SEC_SIZE, src + offset); + return -1; + } + + ret = spi_flash_write_data_safe(dest + offset, s_cache_buf, SPI_FLASH_SEC_SIZE); + if (ret) { + ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", SPI_FLASH_SEC_SIZE, dest + offset); + return -1; + } + } + + return 0; +} + +static inline int esp_set_v2boot_app1(void) +{ + int ret; + size_t offset = s_sys_param.flag ? 1 : 0; + const uint32_t base_addr = CONFIG_SPI_FLASH_SIZE / SPI_FLASH_SEC_SIZE - 3; + const uint32_t sys_addr = (base_addr + 2) * SPI_FLASH_SEC_SIZE; + const uint32_t to_addr = (base_addr + 1 - offset) * SPI_FLASH_SEC_SIZE; + + if (s_boot_param.boot_base.version == 0x2 + || s_boot_param.boot_base.version == 0x1f) { + if (s_boot_param.boot_base.usr_bin == 1) + s_boot_param.boot_base.usr_bin = 0; + else + s_boot_param.boot_base.usr_bin = 1; + } else { + s_boot_param.boot_base.enhance_boot_flag = 1; + if (s_boot_param.boot_base.boot_statue != 0) { + if (s_boot_param.boot_base.usr_bin == 1) + s_boot_param.boot_base.usr_bin = 0; + else + s_boot_param.boot_base.usr_bin = 1; + } + s_boot_param.boot_base.boot_statue = 1; + } + + ESP_LOGD(TAG, "Boot info %x %x %x", s_boot_param.boot_base.usr_bin, s_boot_param.boot_base.boot_statue, s_boot_param.boot_base.version); + + ret = spi_flash_write_data_safe(to_addr, &s_boot_param, sizeof(boot_param_t)); + if (ret) { + ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", sizeof(boot_param_t), to_addr); + return -1; + } + + if (s_sys_param.flag) + s_sys_param.flag = 0; + else + s_sys_param.flag = 1; + + ret = spi_flash_write_data_safe(sys_addr, &s_sys_param, sizeof(sys_param_t)); + if (ret) { + ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", SPI_FLASH_SEC_SIZE, sys_addr); + return -1; + } + + return 0; +} + +static inline int esp_sdk_update_from_v2(void) +{ + const int segment_cnt = 3; + const size_t v2_max_size = 4096; + + uint32_t segment_base = sizeof(esp_image_header_t); + uint32_t segment_size = 0; + + if (s_partition_offset) + return 1; + + for (int i = 0 ; i < segment_cnt; i++) { + int ret; + esp_image_segment_header_t segment; + + ret = spi_flash_read_data(segment_base, &segment, sizeof(esp_image_segment_header_t)); + if (ret) { + ESP_LOGE(TAG, "%d read segment @0x%x is %d", i, segment_base, ret); + return -1UL; + } + + ESP_LOGD(TAG, "data is %x len is %d", segment.load_addr, segment.data_len); + + segment_size += segment.data_len; + + segment_base += sizeof(esp_image_segment_header_t) + segment.data_len; + } + + ESP_LOGD(TAG, "boot total segment size is %u", segment_size); + + return segment_size <= v2_max_size; +} + +int esp_patition_table_init_location(void) +{ + uint32_t addr; + + if (!esp_sdk_update_from_v2()) + return 0; + + addr = esp_get_updated_partition_table_addr(); + if (addr == CONFIG_PARTITION_TABLE_OFFSET) + return 0; + + return esp_flash_sector_copy(CONFIG_PARTITION_TABLE_OFFSET, addr, SPI_FLASH_SEC_SIZE); +} + +int esp_patition_copy_ota1_to_ota0(const void *partition_info) +{ + int ret; + bootloader_state_t *bs = (bootloader_state_t *)partition_info; + + ret = esp_flash_sector_copy(bs->ota[0].offset, bs->ota[1].offset, bs->ota[1].size); + if (ret) { + ESP_LOGE(TAG, "Fail to copy OTA from 0x%x to 0x%x total %d", bs->ota[1].offset, + bs->ota[0].offset, bs->ota[1].size); + return -1; + } + + for (uint32_t offset = 0; offset < bs->ota_info.size; offset += SPI_FLASH_SEC_SIZE) { + ret = spi_flash_erase(bs->ota_info.offset + offset); + if (ret) { + ESP_LOGE(TAG, "Fail to erase OTA data from 0x%x", bs->ota_info.offset + offset); + return -1; + } + } + + return 0; +} + +int esp_patition_table_init_data(void *partition_info) +{ + int ret; + const uint32_t boot_base = 0x1000; + const uint32_t boot_size = CONFIG_SPI_FLASH_SIZE / 2 - boot_base - 4 * SPI_FLASH_SEC_SIZE; + + if (!esp_sdk_update_from_v2()) + return 0; + + if (esp_get_updated_partition_table_addr() == CONFIG_PARTITION_TABLE_OFFSET) + return 0; + + ESP_LOGD(TAG, "Copy firmware1 from %d total %d", boot_base + PARTITION_DATA_OFFSET, boot_size); + + ret = esp_flash_sector_copy(boot_base, boot_base + PARTITION_DATA_OFFSET, boot_size); + if (ret) { + ESP_LOGE(TAG, "Fail to copy V3 bootloader from 0x%x to 0x%x total %d", boot_base + PARTITION_DATA_OFFSET, + boot_base, boot_size); + return -1; + } + + ret = esp_set_v2boot_app1(); + if (ret) { + ESP_LOGE(TAG, "Fail to update V2 bootloader data"); + return -1; + } + + esp_hw_reset(); + + return 0; +} + +#endif /* CONFIG_ESP8266_OTA_FROM_OLD */ diff --git a/components/spi_flash/src/spi_flash.c b/components/spi_flash/src/spi_flash.c index 94e6147e8..a2103f8a0 100644 --- a/components/spi_flash/src/spi_flash.c +++ b/components/spi_flash/src/spi_flash.c @@ -751,3 +751,29 @@ void esp_spi_flash_init(uint32_t spi_speed, uint32_t spi_mode) ESP_EARLY_LOGI("qio_mode", "Enabling default flash chip QIO"); } } + +uintptr_t spi_flash_cache2phys(const void *cached) +{ + uint32_t map_size; + uintptr_t addr_offset; + uintptr_t addr = (uintptr_t)cached; + + const uint32_t reg = REG_READ(CACHE_FLASH_CTRL_REG); + const uint32_t segment = (reg >> CACHE_MAP_SEGMENT_S) & CACHE_MAP_SEGMENT_MASK; + + if (reg & CACHE_MAP_2M) { + map_size = CACHE_2M_SIZE; + addr_offset = 0; + } else { + map_size = CACHE_1M_SIZE; + if (reg & CACHE_MAP_1M_HIGH) + addr_offset = CACHE_1M_SIZE; + else + addr_offset = 0; + } + + if (addr <= CACHE_BASE_ADDR || addr >= CACHE_BASE_ADDR + map_size) + return SPI_FLASH_CACHE2PHYS_FAIL; + + return segment * CACHE_2M_SIZE + (addr + addr_offset - CACHE_BASE_ADDR); +} diff --git a/examples/system/universal_ota/partitions_two_ota_v2tov3.1MB.csv b/examples/system/universal_ota/partitions_two_ota_v2tov3.1MB.csv new file mode 100644 index 000000000..6d3a3a19b --- /dev/null +++ b/examples/system/universal_ota/partitions_two_ota_v2tov3.1MB.csv @@ -0,0 +1,11 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Bootloader is at 0x1000 - 0x8000, total 28KB +# Partition table is at 0x8000 - 0x9000, total 4KB +# Reserve 4 sectors at the end flash address for V2 updating to V3 and system can read V2 parameters. +# If you don't need read v2 parameters, don't reserve the 4 sectors. +nvs, data, nvs, 0x9000, 0x4000 +otadata, data, ota, 0xd000, 0x2000 +phy_init, data, phy, 0xf000, 0x1000 +ota_0, 0, ota_0, 0x10000, 0x6C000 +ota_1, 0, ota_1, 0x90000, 0x6C000 diff --git a/tools/pack_fw.py b/tools/pack_fw.py new file mode 100644 index 000000000..c94d2246c --- /dev/null +++ b/tools/pack_fw.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python2 +# +# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import inspect +import sys +import binascii +import struct + +__version__ = "1.0.1" + +FLASH_SECTOR_SIZE = 0x1000 + +PYTHON2 = sys.version_info[0] < 3 + +def esp8266_crc32(data): + """ + CRC32 algorithm used by 8266 SDK bootloader (and gen_appbin.py). + """ + crc = binascii.crc32(data, 0) & 0xFFFFFFFF + if crc & 0x80000000: + return crc ^ 0xFFFFFFFF + else: + return crc + 1 + +def version(args): + print(__version__) + +# python pack_fw.py addr1 bin1 addr2 bin2 ...... +# The address must increase. + +class proc_addr_file(argparse.Action): + """ Custom parser class for the address/filename pairs passed as arguments """ + def __init__(self, option_strings, dest, nargs='+', **kwargs): + super(proc_addr_file, self).__init__(option_strings, dest, nargs, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + pairs = [] + for i in range(0, len(values) ,2): + try: + address = int(values[i], 0) + except ValueError: + raise argparse.ArgumentError(self, 'Address "%s" must be a number' % values[i]) + try: + argfile = open(values[i + 1], 'rb') + except IOError as e: + raise argparse.ArgumentError(self, e) + pairs.append((address, argfile)) + + end = 0 + pairs = sorted(pairs) + for address, argfile in pairs: + argfile.seek(0,2) # seek to end + size = argfile.tell() + argfile.seek(0) + sector_start = address & ~(FLASH_SECTOR_SIZE - 1) + sector_end = ((address + size + FLASH_SECTOR_SIZE - 1) & ~(FLASH_SECTOR_SIZE - 1)) - 1 + if sector_start < end: + message = 'Detected overlap at address: 0x%x for file: %s' % (address, argfile.name) + raise argparse.ArgumentError(self, message) + end = sector_end + setattr(namespace, self.dest, pairs) + +def pack3(args): + fw_data = '' + + try: + output_file = open(args.output, "w+") + except IOError as e: + print(e) + + end_addr = None + for address, argfile in args.addr_filename: + if address == 0: + address = 4096 + + if end_addr is not None and address > end_addr: + data = (address - end_addr) * ['ff'] + filled = binascii.a2b_hex(''.join(data)) + fw_data += filled + + try: + argfile.seek(0, 0) + data = argfile.read() + fw_data += data + + argfile.seek(0, 2) + end_addr = address + argfile.tell() + except IOError as e: + raise e + + crc32 = esp8266_crc32(fw_data) + fw_data += struct.pack('