{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1745737239,
"reponame":"lws-esp32-factory",
"desc":"ESP32 LWS factory image",
"owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/lws-esp32-factory",
"f":3,
"items": [
{"schema":"libjg2-1",
"cid":"63a7ad271979a6708335d0921fadeb20",
"commit": {"type":"commit",
"time": 1503113048,
"time_ofs": 480,
"oid_tree": { "oid": "53788fc9eba3e4e8594ff7ce6ba93a886cb585d7", "alias": []},
"oid":{ "oid": "29718be6b00c2a8e4b3ef260ca20eca25ac5090e", "alias": []},
"msg": "set bootloader copy to v3 esp-idf unchanged",
"sig_commit": { "git_time": { "time": 1503113048, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1503113048, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "set bootloader copy to v3 esp-idf unchanged"
,
"diff": "diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild\nindex be3ec5f..a8c1006 100644\n--- a/components/bootloader/Makefile.projbuild\n+++ b/components/bootloader/Makefile.projbuild\n@@ -1,15 +1,13 @@\n-#\n-# Bootloader component\n+# Bootloader component (top-level project parts)\n #\n # The bootloader is not a real component that gets linked into the project.\n-# Instead it is an entire standalone project ( in src/) that gets built in \n-# the upper projects build directory. This Makefile.projbuild provides the \n-# glue to build the bootloader project from the original project. It \n-# basically runs Make in the src/ directory but it needs to zero some variables\n-# the ESP-IDF project.mk makefile exports first, to not let them interfere.\n+# Instead it is an entire standalone project (in subproject/) that gets\n+# built in the upper project's build directory. This Makefile.projbuild provides\n+# the glue to build the bootloader project from the original project. It\n+# basically runs Make in the subproject/ directory but it needs to\n+# zero some variables the ESP-IDF project.mk makefile exports first, to not\n+# let them interfere.\n #\n-ifndef IS_BOOTLOADER_BUILD\n-\n BOOTLOADER_COMPONENT_PATH :\u003d $(COMPONENT_PATH)\n BOOTLOADER_BUILD_DIR\u003d$(abspath $(BUILD_DIR_BASE)/bootloader)\n BOOTLOADER_BIN\u003d$(BOOTLOADER_BUILD_DIR)/bootloader.bin\n@@ -22,16 +20,29 @@ export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component\n BOOTLOADER_OFFSET :\u003d 0x1000\n \n # Custom recursive make for bootloader sub-project\n-BOOTLOADER_MAKE\u003d+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \u005c\n-\tV\u003d$(V) BUILD_DIR_BASE\u003d$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS\u003d TESTS_ALL\u003d\n-\n-.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)\n+#\n+# NB: Some variables are cleared in the environment, not\n+# overriden, because they need to be re-defined in the child\n+# project.\n+BOOTLOADER_MAKE\u003d +\u005c\n+\tPROJECT_PATH\u003d \u005c\n+\tCOMPONENT_DIRS\u003d \u005c\n+\t$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/subproject \u005c\n+\tV\u003d$(V) \u005c\n+\tBUILD_DIR_BASE\u003d$(BOOTLOADER_BUILD_DIR) \u005c\n+\tTEST_COMPONENTS\u003d \u005c\n+\tTESTS_ALL\u003d\n+\n+.PHONY: bootloader-clean bootloader-flash bootloader-list-components bootloader $(BOOTLOADER_BIN)\n \n $(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE)\n \t$(BOOTLOADER_MAKE) $@\n \n clean: bootloader-clean\n \n+bootloader-list-components:\n+\t$(BOOTLOADER_MAKE) list-components\n+\n ifndef CONFIG_SECURE_BOOT_ENABLED\n # If secure boot disabled, bootloader flashing is integrated\n # with 'make flash' and no warnings are printed.\n@@ -110,11 +121,3 @@ endif\n bootloader-clean:\n \t$(BOOTLOADER_MAKE) app-clean\n \trm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN)\n-\n-$(BOOTLOADER_BUILD_DIR):\n-\tmkdir -p $@\n-\n-else\n-CFLAGS +\u003d -D BOOTLOADER_BUILD\u003d1 -I $(IDF_PATH)/components/esp32/include\n-\n-endif\ndiff --git a/components/bootloader/src/.gitignore b/components/bootloader/src/.gitignore\ndeleted file mode 100644\nindex 278a862..0000000\n--- a/components/bootloader/src/.gitignore\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-build\n-sdkconfig\ndiff --git a/components/bootloader/src/Makefile b/components/bootloader/src/Makefile\ndeleted file mode 100644\nindex ac71e27..0000000\n--- a/components/bootloader/src/Makefile\n+++ /dev/null\n@@ -1,21 +0,0 @@\n-#\n-# This is a project Makefile. It is assumed the directory this Makefile resides in is a\n-# project subdirectory.\n-#\n-\n-PROJECT_NAME :\u003d bootloader\n-\n-#We cannot include the esp32 component directly but we need its includes.\n-#This is fixed by adding CFLAGS from Makefile.projbuild\n-COMPONENTS :\u003d esptool_py bootloader bootloader_support log spi_flash micro-ecc soc\n-\n-# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.\n-#\n-# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op\n-IS_BOOTLOADER_BUILD :\u003d 1\n-export IS_BOOTLOADER_BUILD\n-\n-# include the top-level \u0022project\u0022 include directory, for sdkconfig.h\n-CFLAGS +\u003d -I$(BUILD_DIR_BASE)/../include\n-\n-include $(IDF_PATH)/make/project.mk\ndiff --git a/components/bootloader/src/main/Makefile.projbuild b/components/bootloader/src/main/Makefile.projbuild\ndeleted file mode 100644\nindex c368c68..0000000\n--- a/components/bootloader/src/main/Makefile.projbuild\n+++ /dev/null\n@@ -1,4 +0,0 @@\n-# Submodules normally added in component.mk, but fully qualified\n-# paths can be added at this level (we need binary librtc to be\n-# available to link bootloader).\n-COMPONENT_SUBMODULES +\u003d $(IDF_PATH)/components/esp32/lib\ndiff --git a/components/bootloader/src/main/bootloader_config.h b/components/bootloader/src/main/bootloader_config.h\ndeleted file mode 100644\nindex 6b37899..0000000\n--- a/components/bootloader/src/main/bootloader_config.h\n+++ /dev/null\n@@ -1,53 +0,0 @@\n-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n-//\n-// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n-// you may not use this file except in compliance with the License.\n-// You may obtain a copy of the License at\n-\n-// http://www.apache.org/licenses/LICENSE-2.0\n-//\n-// Unless required by applicable law or agreed to in writing, software\n-// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-// See the License for the specific language governing permissions and\n-// limitations under the License.\n-#ifndef __BOOT_CONFIG_H__\n-#define __BOOT_CONFIG_H__\n-\n-#include \u003cstdint.h\u003e\n-\n-#ifdef __cplusplus\n-extern \u0022C\u0022\n-{\n-#endif\n-\n-#include \u0022esp_flash_data_types.h\u0022\n-\n-#define SPI_SEC_SIZE 0x1000\n-#define IROM_LOW 0x400D0000\n-#define IROM_HIGH 0x40400000\n-#define DROM_LOW 0x3F400000\n-#define DROM_HIGH 0x3F800000\n-#define RTC_IRAM_LOW 0x400C0000\n-#define RTC_IRAM_HIGH 0x400C2000\n-#define RTC_DATA_LOW 0x50000000\n-#define RTC_DATA_HIGH 0x50002000\n-\n-#define SPI_ERROR_LOG \u0022spi flash error\u0022\n-\n-typedef struct {\n- esp_partition_pos_t ota_info;\n- esp_partition_pos_t factory;\n- esp_partition_pos_t test;\n- esp_partition_pos_t ota[16];\n- uint32_t app_count;\n- uint32_t selected_subtype;\n-} bootloader_state_t;\n-\n-bool flash_encrypt(bootloader_state_t *bs);\n-\n-#ifdef __cplusplus\n-}\n-#endif\n-\n-#endif /* __BOOT_CONFIG_H__ */\ndiff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c\ndeleted file mode 100644\nindex 27d527a..0000000\n--- a/components/bootloader/src/main/bootloader_start.c\n+++ /dev/null\n@@ -1,802 +0,0 @@\n-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n-//\n-// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n-// you may not use this file except in compliance with the License.\n-// You may obtain a copy of the License at\n-//\n-// http://www.apache.org/licenses/LICENSE-2.0\n-//\n-// Unless required by applicable law or agreed to in writing, software\n-// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-// See the License for the specific language governing permissions and\n-// limitations under the License.\n-#include \u003cstring.h\u003e\n-#include \u003cstdint.h\u003e\n-#include \u003climits.h\u003e\n-\n-#include \u0022esp_attr.h\u0022\n-#include \u0022esp_log.h\u0022\n-\n-#include \u0022rom/cache.h\u0022\n-#include \u0022rom/ets_sys.h\u0022\n-#include \u0022rom/spi_flash.h\u0022\n-#include \u0022rom/crc.h\u0022\n-#include \u0022rom/rtc.h\u0022\n-#include \u0022rom/uart.h\u0022\n-#include \u0022rom/gpio.h\u0022\n-#include \u0022rom/secure_boot.h\u0022\n-\n-#include \u0022soc/soc.h\u0022\n-#include \u0022soc/cpu.h\u0022\n-#include \u0022soc/dport_reg.h\u0022\n-#include \u0022soc/io_mux_reg.h\u0022\n-#include \u0022soc/efuse_reg.h\u0022\n-#include \u0022soc/rtc_cntl_reg.h\u0022\n-#include \u0022soc/timer_group_reg.h\u0022\n-#include \u0022soc/gpio_reg.h\u0022\n-#include \u0022soc/gpio_sig_map.h\u0022\n-#include \u0022soc/rtc_io_reg.h\u0022\n-\n-#include \u0022sdkconfig.h\u0022\n-#include \u0022esp_image_format.h\u0022\n-#include \u0022esp_secure_boot.h\u0022\n-#include \u0022esp_flash_encrypt.h\u0022\n-#include \u0022esp_flash_partitions.h\u0022\n-#include \u0022bootloader_flash.h\u0022\n-#include \u0022bootloader_random.h\u0022\n-#include \u0022bootloader_config.h\u0022\n-#include \u0022soc/rtc.h\u0022\n-#include \u0022flash_qio_mode.h\u0022\n-\n-extern int _bss_start;\n-extern int _bss_end;\n-\n-static const char* TAG \u003d \u0022boot\u0022;\n-/*\n-We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,\n-flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C.\n-*/\n-\n-// TODO: make a nice header file for ROM functions instead of adding externs all over the place\n-extern void Cache_Flush(int);\n-\n-void bootloader_main();\n-static int unpack_load_app(const esp_partition_pos_t *app_node);\n-void print_flash_info(const esp_image_header_t* pfhdr);\n-static void set_cache_and_start_app(uint32_t drom_addr,\n- uint32_t drom_load_addr,\n- uint32_t drom_size,\n- uint32_t irom_addr,\n- uint32_t irom_load_addr,\n- uint32_t irom_size,\n- uint32_t entry_addr);\n-static void update_flash_config(const esp_image_header_t* pfhdr);\n-static void uart_console_configure(void);\n-\n-#undef ESP_LOGI\n-#define ESP_LOGI(x, y, ...) \n-\n-void IRAM_ATTR call_start_cpu0()\n-{\n- cpu_configure_region_protection();\n-\n- //Clear bss\n- memset(\u0026_bss_start, 0, (\u0026_bss_end - \u0026_bss_start) * sizeof(_bss_start));\n-\n- /* completely reset MMU for both CPUs\n- (in case serial bootloader was running) */\n- Cache_Read_Disable(0);\n- Cache_Read_Disable(1);\n- Cache_Flush(0);\n- Cache_Flush(1);\n- mmu_init(0);\n- REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);\n- mmu_init(1);\n- REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);\n- /* (above steps probably unnecessary for most serial bootloader\n- usage, all that's absolutely needed is that we unmask DROM0\n- cache on the following two lines - normal ROM boot exits with\n- DROM0 cache unmasked, but serial bootloader exits with it\n- masked. However can't hurt to be thorough and reset\n- everything.)\n-\n- The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are\n- necessary to work around a hardware bug.\n- */\n- REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);\n- REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);\n-\n- bootloader_main();\n-}\n-\n-\n-/** @brief Load partition table\n- *\n- * Parse partition table, get useful data such as location of\n- * OTA data partition, factory app partition, and test app partition.\n- *\n- * @param bs bootloader state structure used to save read data\n- * @return return true if the partition table was succesfully loaded and MD5 checksum is valid.\n- */\n-bool load_partition_table(bootloader_state_t* bs)\n-{\n- const esp_partition_info_t *partitions;\n- const int ESP_PARTITION_TABLE_DATA_LEN \u003d 0xC00; /* length of actual data (signature is appended to this) */\n- char *partition_usage;\n- esp_err_t err;\n- int num_partitions;\n-\n- (void)partition_usage;\n-\n-#ifdef CONFIG_SECURE_BOOT_ENABLED\n- if(esp_secure_boot_enabled()) {\n- ESP_LOGI(TAG, \u0022Verifying partition table signature...\u0022);\n- err \u003d esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);\n- if (err !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022Failed to verify partition table signature.\u0022);\n- return false;\n- }\n- ESP_LOGD(TAG, \u0022Partition table signature verified\u0022);\n- }\n-#endif\n-\n- partitions \u003d bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);\n- if (!partitions) {\n- ESP_LOGE(TAG, \u0022bootloader_mmap(0x%x, 0x%x) failed\u0022, ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);\n- return false;\n- }\n- ESP_LOGD(TAG, \u0022mapped partition table 0x%x at 0x%x\u0022, ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);\n-\n- err \u003d esp_partition_table_basic_verify(partitions, true, \u0026num_partitions);\n- if (err !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022Failed to verify partition table\u0022);\n- return false;\n- }\n-\n- ESP_LOGI(TAG, \u0022Partition Table:\u0022);\n- ESP_LOGI(TAG, \u0022## Label Usage Type ST Offset Length\u0022);\n-\n- for(int i \u003d 0; i \u003c num_partitions; i++) {\n- const esp_partition_info_t *partition \u003d \u0026partitions[i];\n- ESP_LOGD(TAG, \u0022load partition table entry 0x%x\u0022, (intptr_t)partition);\n- ESP_LOGD(TAG, \u0022type\u003d%x subtype\u003d%x\u0022, partition-\u003etype, partition-\u003esubtype);\n- partition_usage \u003d \u0022unknown\u0022;\n-\n- /* valid partition table */\n- switch(partition-\u003etype) {\n- case PART_TYPE_APP: /* app partition */\n- switch(partition-\u003esubtype) {\n- case PART_SUBTYPE_FACTORY: /* factory binary */\n- bs-\u003efactory \u003d partition-\u003epos;\n- partition_usage \u003d \u0022factory app\u0022;\n- break;\n- case PART_SUBTYPE_TEST: /* test binary */\n- bs-\u003etest \u003d partition-\u003epos;\n- partition_usage \u003d \u0022test app\u0022;\n- break;\n- default:\n- /* OTA binary */\n- if ((partition-\u003esubtype \u0026 ~PART_SUBTYPE_OTA_MASK) \u003d\u003d PART_SUBTYPE_OTA_FLAG) {\n- bs-\u003eota[partition-\u003esubtype \u0026 PART_SUBTYPE_OTA_MASK] \u003d partition-\u003epos;\n- ++bs-\u003eapp_count;\n- partition_usage \u003d \u0022OTA app\u0022;\n- }\n- else {\n- partition_usage \u003d \u0022Unknown app\u0022;\n- }\n- break;\n- }\n- break; /* PART_TYPE_APP */\n- case PART_TYPE_DATA: /* data partition */\n- switch(partition-\u003esubtype) {\n- case PART_SUBTYPE_DATA_OTA: /* ota data */\n- bs-\u003eota_info \u003d partition-\u003epos;\n- partition_usage \u003d \u0022OTA data\u0022;\n- break;\n- case PART_SUBTYPE_DATA_RF:\n- partition_usage \u003d \u0022RF data\u0022;\n- break;\n- case PART_SUBTYPE_DATA_WIFI:\n- partition_usage \u003d \u0022WiFi data\u0022;\n- break;\n- default:\n- partition_usage \u003d \u0022Unknown data\u0022;\n- break;\n- }\n- break; /* PARTITION_USAGE_DATA */\n- default: /* other partition type */\n- break;\n- }\n-\n- /* print partition type info */\n- ESP_LOGI(TAG, \u0022%2d %-16s %-16s %02x %02x %08x %08x\u0022, i, partition-\u003elabel, partition_usage,\n- partition-\u003etype, partition-\u003esubtype,\n- partition-\u003epos.offset, partition-\u003epos.size);\n- }\n-\n- bootloader_munmap(partitions);\n-\n- ESP_LOGI(TAG,\u0022End of partition table\u0022);\n- return true;\n-}\n-\n-static uint32_t ota_select_crc(const esp_ota_select_entry_t *s)\n-{\n- return crc32_le(UINT32_MAX, (uint8_t*)\u0026s-\u003eota_seq, 4);\n-}\n-\n-static bool ota_select_valid(const esp_ota_select_entry_t *s)\n-{\n- return s-\u003eota_seq !\u003d UINT32_MAX \u0026\u0026 s-\u003ecrc \u003d\u003d ota_select_crc(s);\n-}\n-\n-static bool check_force_button(void)\n-{\n-\tvolatile int n;\n-\n-\tgpio_pad_select_gpio(CONFIG_BOOTLOADER_FACTORY_BUTTON_GPIO);\n-\tGPIO_DIS_OUTPUT(CONFIG_BOOTLOADER_FACTORY_BUTTON_GPIO);\n-\tgpio_pad_unhold(CONFIG_BOOTLOADER_FACTORY_BUTTON_GPIO);\n-\tgpio_pad_pullup(CONFIG_BOOTLOADER_FACTORY_BUTTON_GPIO);\n-\n-//\t*((volatile uint32_t *)PERIPHS_IO_MUX_GPIO34_U) \u003d FUNC_GPIO34_GPIO34_0;\n-//\t*((volatile uint32_t *)GPIO_ENABLE1_REG) \u0026\u003d ~(1 \u003c\u003c (CONFIG_BOOTLOADER_FACTORY_BUTTON_GPIO - 32));\n-//\t*((volatile uint32_t *)RTC_IO_TOUCH_PAD4_REG) |\u003d RTC_IO_TOUCH_PAD4_TO_GPIO | RTC_IO_TOUCH_PAD4_FUN_IE | RTC_IO_TOUCH_PAD4_MUX_SEL;\n-\tfor (n \u003d 0; n \u003c 50; n++)\n-\t\t;\n-\treturn !GPIO_INPUT_GET(CONFIG_BOOTLOADER_FACTORY_BUTTON_GPIO);\n-}\n-\n-#define LWS_MAGIC_REBOOT_TYPE_ADS 0x50001ffc\n-#define LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY 0xb00bcafe\n-#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY 0xfaceb00b\n-#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON 0xf0cedfac\n-\n-/**\n- * @function : bootloader_main\n- * @description: entry function of 2nd bootloader\n- *\n- * @inputs: void\n- */\n-\n-void bootloader_main()\n-{\n-\tint force_factory \u003d 0;\n-\n- \t/* Set CPU to 80MHz. Keep other clocks unmodified. */\n- uart_tx_wait_idle(0);\n- rtc_clk_config_t clk_cfg \u003d RTC_CLK_CONFIG_DEFAULT();\n- clk_cfg.cpu_freq \u003d RTC_CPU_FREQ_80M;\n- clk_cfg.slow_freq \u003d rtc_clk_slow_freq_get();\n- clk_cfg.fast_freq \u003d rtc_clk_fast_freq_get();\n- rtc_clk_init(clk_cfg);\n-\n- uart_console_configure();\n-\n-again:\n-\n- ESP_LOGI(TAG, \u0022ESP-IDF %s 2nd stage bootloader\u0022, IDF_VER);\n-#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)\n- esp_err_t err;\n-#endif\n- esp_image_header_t fhdr;\n- bootloader_state_t bs;\n- esp_rom_spiflash_result_t spiRet1,spiRet2;\n- esp_ota_select_entry_t sa,sb;\n- const esp_ota_select_entry_t *ota_select_map;\n-\n- /* we can leave a magic at end of fast RTC ram to force next boot into FACTORY */\n-\tuint32_t *p_force_factory_magic \u003d (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;\n-\n-\tif (*p_force_factory_magic \u003d\u003d LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY) {\n-\t\tforce_factory \u003d 1;\n-\t\t/* mark as having been forced... needed to fixup wrong reported boot part */\n-\t\t*p_force_factory_magic \u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY;\n-\t} else\n-\t\t*p_force_factory_magic \u003d 0;\n-\n-\tif (check_force_button()) {\n-\t\tforce_factory \u003d 1;\n-\t\tESP_LOGE(TAG, \u0022Force Button is Down 0x%x\u005cn\u0022, gpio_input_get());\n-\t\t*p_force_factory_magic \u003d LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON;\n-\t}\n-\n- memset(\u0026bs, 0, sizeof(bs));\n-\n- ESP_LOGI(TAG, \u0022compile time \u0022 __TIME__ );\n- /* disable watch dog here */\n- REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );\n- REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );\n- esp_rom_spiflash_unlock();\n-\n- ESP_LOGI(TAG, \u0022Enabling RNG early entropy source...\u0022);\n- bootloader_random_enable();\n-\n-#if CONFIG_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT\n- bootloader_enable_qio_mode();\n-#endif\n-\n- if(esp_image_load_header(0x1000, true, \u0026fhdr) !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022failed to load bootloader header!\u0022);\n- return;\n- }\n-\n- print_flash_info(\u0026fhdr);\n-\n- update_flash_config(\u0026fhdr);\n-\n- if (!load_partition_table(\u0026bs)) {\n- ESP_LOGE(TAG, \u0022load partition table error!\u0022);\n- return;\n- }\n-\n- esp_partition_pos_t load_part_pos;\n- ESP_LOGE(TAG, \u0022force_factory %d bs.ota_info.offset %d\u005cn\u0022, force_factory, bs.ota_info.offset);\n-\n- if (!force_factory \u0026\u0026 bs.ota_info.offset !\u003d 0) { // check if partition table has OTA info partition\n- //ESP_LOGE(\u0022OTA info sector handling is not implemented\u0022);\n- if (bs.ota_info.size \u003c 2 * SPI_SEC_SIZE) {\n- ESP_LOGE(TAG, \u0022ERROR: ota_info partition size %d is too small (minimum %d bytes)\u0022, bs.ota_info.size, sizeof(esp_ota_select_entry_t));\n- return;\n- }\n-\n- ota_select_map \u003d bootloader_mmap(bs.ota_info.offset, bs.ota_info.size);\n- if (!ota_select_map) {\n- ESP_LOGE(TAG, \u0022bootloader_mmap(0x%x, 0x%x) failed\u0022, bs.ota_info.offset, bs.ota_info.size);\n- return;\n- }\n- memcpy(\u0026sa, ota_select_map, sizeof(esp_ota_select_entry_t));\n- memcpy(\u0026sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));\n- bootloader_munmap(ota_select_map);\n- if(sa.ota_seq \u003d\u003d 0xFFFFFFFF \u0026\u0026 sb.ota_seq \u003d\u003d 0xFFFFFFFF) {\n-\n- \t\t// this info is just erased flash\n-\n- if (bs.factory.offset !\u003d 0) {\n-\t\t/*\n-\t\t * in other words, nobody set the logical OTA\n-\t\t * pointer yet, but we do have the factory image\n-\t\t */\n-\n- \t\t load_part_pos \u003d bs.factory;\n- } else {\n- load_part_pos \u003d bs.ota[0];\n- sa.ota_seq \u003d 0x01;\n- sa.crc \u003d ota_select_crc(\u0026sa);\n- sb.ota_seq \u003d 0x00;\n- sb.crc \u003d ota_select_crc(\u0026sb);\n-\n- Cache_Read_Disable(0); \n- spiRet1 \u003d esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000);\n- spiRet2 \u003d esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000+1);\n- if (spiRet1 !\u003d ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 !\u003d ESP_ROM_SPIFLASH_RESULT_OK ) { \n- ESP_LOGE(TAG, SPI_ERROR_LOG);\n- return;\n- } \n- spiRet1 \u003d esp_rom_spiflash_write(bs.ota_info.offset,(uint32_t *)\u0026sa,sizeof(esp_ota_select_entry_t));\n- spiRet2 \u003d esp_rom_spiflash_write(bs.ota_info.offset + 0x1000,(uint32_t *)\u0026sb,sizeof(esp_ota_select_entry_t));\n- if (spiRet1 !\u003d ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 !\u003d ESP_ROM_SPIFLASH_RESULT_OK ) { \n- ESP_LOGE(TAG, SPI_ERROR_LOG);\n- return;\n- } \n- Cache_Read_Enable(0);\n- }\n- //TODO:write data in ota info\n- } else {\n- if(ota_select_valid(\u0026sa) \u0026\u0026 ota_select_valid(\u0026sb)) {\n- load_part_pos \u003d bs.ota[(((sa.ota_seq \u003e sb.ota_seq)?sa.ota_seq:sb.ota_seq) - 1)%bs.app_count];\n- } else if(ota_select_valid(\u0026sa)) {\n- load_part_pos \u003d bs.ota[(sa.ota_seq - 1) % bs.app_count];\n- } else if(ota_select_valid(\u0026sb)) {\n- load_part_pos \u003d bs.ota[(sb.ota_seq - 1) % bs.app_count];\n- } else if (bs.factory.offset !\u003d 0) {\n- ESP_LOGE(TAG, \u0022ota data partition invalid, falling back to factory\u0022);\n- load_part_pos \u003d bs.factory;\n- } else {\n- ESP_LOGE(TAG, \u0022ota data partition invalid and no factory, can't boot\u0022);\n- return;\n- }\n- }\n- } else if (bs.factory.offset !\u003d 0) { // otherwise, look for factory app partition\n- load_part_pos \u003d bs.factory;\n- } else if (bs.test.offset !\u003d 0) { // otherwise, look for test app parition\n- load_part_pos \u003d bs.test;\n- } else { // nothing to load, bail out\n- ESP_LOGE(TAG, \u0022nothing to load\u0022);\n- return;\n- }\n-\n-#ifdef CONFIG_SECURE_BOOT_ENABLED\n- /* Generate secure digest from this bootloader to protect future\n- modifications */\n- ESP_LOGI(TAG, \u0022Checking secure boot...\u0022);\n- err \u003d esp_secure_boot_permanently_enable();\n- if (err !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.\u0022, err);\n- /* Allow booting to continue, as the failure is probably\n- due to user-configured EFUSEs for testing...\n- */\n- }\n-#endif\n-\n-#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED\n- /* encrypt flash */\n- ESP_LOGI(TAG, \u0022Checking flash encryption...\u0022);\n- bool flash_encryption_enabled \u003d esp_flash_encryption_enabled();\n- err \u003d esp_flash_encrypt_check_and_update();\n- if (err !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022Flash encryption check failed (%d).\u0022, err);\n- return;\n- }\n-\n- if (!flash_encryption_enabled \u0026\u0026 esp_flash_encryption_enabled()) {\n- /* Flash encryption was just enabled for the first time,\n- so issue a system reset to ensure flash encryption\n- cache resets properly */\n- ESP_LOGI(TAG, \u0022Resetting with flash encryption enabled...\u0022);\n- REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);\n- return;\n- }\n-#endif\n-\n- ESP_LOGI(TAG, \u0022Disabling RNG early entropy source...\u0022);\n- bootloader_random_disable();\n-\n- // copy loaded segments to RAM, set up caches for mapped segments, and start application\n- ESP_LOGI(TAG, \u0022Loading app partition at offset %08x\u0022, load_part_pos);\n- if (unpack_load_app(\u0026load_part_pos)) {\n-\t force_factory \u003d 1;\n-\t goto again;\n- }\n-}\n-\n-static int unpack_load_app(const esp_partition_pos_t* partition)\n-{\n- esp_err_t err;\n- esp_image_header_t image_header;\n- uint32_t image_length;\n-\n- /* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */\n- err \u003d esp_image_basic_verify(partition-\u003eoffset, true, \u0026image_length);\n- if (err !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022Failed to verify app image @ 0x%x (%d)\u0022, partition-\u003eoffset, err);\n- return 1;\n- }\n-\n-#ifdef CONFIG_SECURE_BOOT_ENABLED\n- if (esp_secure_boot_enabled()) {\n- ESP_LOGI(TAG, \u0022Verifying app signature @ 0x%x (length 0x%x)\u0022, partition-\u003eoffset, image_length);\n- err \u003d esp_secure_boot_verify_signature(partition-\u003eoffset, image_length);\n- if (err !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022App image @ 0x%x failed signature verification (%d)\u0022, partition-\u003eoffset, err);\n- return 1;\n- }\n- ESP_LOGD(TAG, \u0022App signature is valid\u0022);\n- }\n-#endif\n-\n- if (esp_image_load_header(partition-\u003eoffset, true, \u0026image_header) !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022Failed to load app image header @ 0x%x\u0022, partition-\u003eoffset);\n- return 1;\n- }\n-\n- uint32_t drom_addr \u003d 0;\n- uint32_t drom_load_addr \u003d 0;\n- uint32_t drom_size \u003d 0;\n- uint32_t irom_addr \u003d 0;\n- uint32_t irom_load_addr \u003d 0;\n- uint32_t irom_size \u003d 0;\n-\n- /* Reload the RTC memory segments whenever a non-deepsleep reset\n- is occurring */\n- bool load_rtc_memory \u003d rtc_get_reset_reason(0) !\u003d DEEPSLEEP_RESET;\n-\n- ESP_LOGD(TAG, \u0022bin_header: %u %u %u %u %08x\u0022, image_header.magic,\n- image_header.segment_count,\n- image_header.spi_mode,\n- image_header.spi_size,\n- (unsigned)image_header.entry_addr);\n-\n- /* Important: From here on this function cannot access any global data (bss/data segments),\n- as loading the app image may overwrite these.\n- */\n- for (int segment \u003d 0; segment \u003c image_header.segment_count; segment++) {\n- esp_image_segment_header_t segment_header;\n- uint32_t data_offs;\n- if(esp_image_load_segment_header(segment, partition-\u003eoffset,\n- \u0026image_header, true,\n- \u0026segment_header, \u0026data_offs) !\u003d ESP_OK) {\n- ESP_LOGE(TAG, \u0022failed to load segment header #%d\u0022, segment);\n- return 1;\n- }\n-\n- const uint32_t address \u003d segment_header.load_addr;\n- bool load \u003d true;\n- bool map \u003d false;\n- if (address \u003d\u003d 0x00000000) { // padding, ignore block\n- load \u003d false;\n- }\n- if (address \u003d\u003d 0x00000004) {\n- load \u003d false; // md5 checksum block\n- // TODO: actually check md5\n- }\n-\t(void)map;\n- if (address \u003e\u003d DROM_LOW \u0026\u0026 address \u003c DROM_HIGH) {\n- ESP_LOGD(TAG, \u0022found drom segment, map from %08x to %08x\u0022, data_offs,\n- segment_header.load_addr);\n- drom_addr \u003d data_offs;\n- drom_load_addr \u003d segment_header.load_addr;\n- drom_size \u003d segment_header.data_len + sizeof(segment_header);\n- load \u003d false;\n- map \u003d true;\n- }\n-\n- if (address \u003e\u003d IROM_LOW \u0026\u0026 address \u003c IROM_HIGH) {\n- ESP_LOGD(TAG, \u0022found irom segment, map from %08x to %08x\u0022, data_offs,\n- segment_header.load_addr);\n- irom_addr \u003d data_offs;\n- irom_load_addr \u003d segment_header.load_addr;\n- irom_size \u003d segment_header.data_len + sizeof(segment_header);\n- load \u003d false;\n- map \u003d true;\n- }\n-\n- if (!load_rtc_memory \u0026\u0026 address \u003e\u003d RTC_IRAM_LOW \u0026\u0026 address \u003c RTC_IRAM_HIGH) {\n- ESP_LOGD(TAG, \u0022Skipping RTC code segment at %08x\u005cn\u0022, data_offs);\n- load \u003d false;\n- }\n-\n- if (!load_rtc_memory \u0026\u0026 address \u003e\u003d RTC_DATA_LOW \u0026\u0026 address \u003c RTC_DATA_HIGH) {\n- ESP_LOGD(TAG, \u0022Skipping RTC data segment at %08x\u005cn\u0022, data_offs);\n- load \u003d false;\n- }\n-\n- ESP_LOGI(TAG, \u0022segment %d: paddr\u003d0x%08x vaddr\u003d0x%08x size\u003d0x%05x (%6d) %s\u0022, segment, data_offs - sizeof(esp_image_segment_header_t),\n- segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?\u0022load\u0022:(map)?\u0022map\u0022:\u0022\u0022);\n-\n- if (load) {\n- intptr_t sp, start_addr, end_addr;\n- ESP_LOGV(TAG, \u0022bootloader_mmap data_offs\u003d%08x data_len\u003d%08x\u0022, data_offs, segment_header.data_len);\n-\n- start_addr \u003d segment_header.load_addr;\n- end_addr \u003d start_addr + segment_header.data_len;\n-\n- /* Before loading segment, check it doesn't clobber\n- bootloader RAM... */\n-\n- if (end_addr \u003c 0x40000000) {\n- sp \u003d (intptr_t)get_sp();\n- if (end_addr \u003e sp) {\n- ESP_LOGE(TAG, \u0022Segment %d end address %08x overlaps bootloader stack %08x - can't load\u0022,\n- segment, end_addr, sp);\n- return 1;\n- }\n- if (end_addr \u003e sp - 256) {\n- /* We don't know for sure this is the stack high water mark, so warn if\n- it seems like we may overflow.\n- */\n- ESP_LOGW(TAG, \u0022Segment %d end address %08x close to stack pointer %08x\u0022,\n- segment, end_addr, sp);\n- }\n- }\n-\n- const void *data \u003d bootloader_mmap(data_offs, segment_header.data_len);\n- if(!data) {\n- ESP_LOGE(TAG, \u0022bootloader_mmap(0x%xc, 0x%x) failed\u0022,\n- data_offs, segment_header.data_len);\n- return 1;\n- }\n- memcpy((void *)segment_header.load_addr, data, segment_header.data_len);\n- bootloader_munmap(data);\n- }\n- }\n-\n- set_cache_and_start_app(drom_addr,\n- drom_load_addr,\n- drom_size,\n- irom_addr,\n- irom_load_addr,\n- irom_size,\n- image_header.entry_addr);\n-\n- return 0;\n-}\n-\n-static void set_cache_and_start_app(\n- uint32_t drom_addr,\n- uint32_t drom_load_addr,\n- uint32_t drom_size,\n- uint32_t irom_addr,\n- uint32_t irom_load_addr,\n- uint32_t irom_size, \n- uint32_t entry_addr)\n-{\n- ESP_LOGD(TAG, \u0022configure drom and irom and start\u0022);\n- Cache_Read_Disable( 0 );\n- Cache_Flush( 0 );\n- uint32_t drom_page_count \u003d (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k\n- ESP_LOGV(TAG, \u0022d mmu set paddr\u003d%08x vaddr\u003d%08x size\u003d%d n\u003d%d\u0022, drom_addr \u0026 0xffff0000, drom_load_addr \u0026 0xffff0000, drom_size, drom_page_count );\n- int rc \u003d cache_flash_mmu_set( 0, 0, drom_load_addr \u0026 0xffff0000, drom_addr \u0026 0xffff0000, 64, drom_page_count );\n- ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n- rc \u003d cache_flash_mmu_set( 1, 0, drom_load_addr \u0026 0xffff0000, drom_addr \u0026 0xffff0000, 64, drom_page_count );\n- ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n- uint32_t irom_page_count \u003d (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k\n- ESP_LOGV(TAG, \u0022i mmu set paddr\u003d%08x vaddr\u003d%08x size\u003d%d n\u003d%d\u0022, irom_addr \u0026 0xffff0000, irom_load_addr \u0026 0xffff0000, irom_size, irom_page_count );\n- rc \u003d cache_flash_mmu_set( 0, 0, irom_load_addr \u0026 0xffff0000, irom_addr \u0026 0xffff0000, 64, irom_page_count );\n- ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n- rc \u003d cache_flash_mmu_set( 1, 0, irom_load_addr \u0026 0xffff0000, irom_addr \u0026 0xffff0000, 64, irom_page_count );\n- ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n- REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 \u0026 0) | (DPORT_PRO_CACHE_MASK_IROM0 \u0026 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );\n- REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 \u0026 0) | (DPORT_APP_CACHE_MASK_IROM0 \u0026 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );\n- Cache_Read_Enable( 0 );\n-\n- // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)\n-\n- ESP_LOGD(TAG, \u0022start: 0x%08x\u0022, entry_addr);\n- typedef void (*entry_t)(void);\n- entry_t entry \u003d ((entry_t) entry_addr);\n-\n- // TODO: we have used quite a bit of stack at this point.\n- // use \u0022movsp\u0022 instruction to reset stack back to where ROM stack starts.\n- (*entry)();\n-}\n-\n-static void update_flash_config(const esp_image_header_t* pfhdr)\n-{\n- uint32_t size;\n- switch(pfhdr-\u003espi_size) {\n- case ESP_IMAGE_FLASH_SIZE_1MB:\n- size \u003d 1;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_2MB:\n- size \u003d 2;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_4MB:\n- size \u003d 4;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_8MB:\n- size \u003d 8;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_16MB:\n- size \u003d 16;\n- break;\n- default:\n- size \u003d 2;\n- }\n- Cache_Read_Disable( 0 );\n- // Set flash chip size\n- esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);\n- // TODO: set mode\n- // TODO: set frequency\n- Cache_Flush(0);\n- Cache_Read_Enable( 0 );\n-}\n-\n-void print_flash_info(const esp_image_header_t* phdr)\n-{\n-#if (BOOT_LOG_LEVEL \u003e\u003d BOOT_LOG_LEVEL_NOTICE)\n-\n- ESP_LOGD(TAG, \u0022magic %02x\u0022, phdr-\u003emagic );\n- ESP_LOGD(TAG, \u0022segments %02x\u0022, phdr-\u003esegment_count );\n- ESP_LOGD(TAG, \u0022spi_mode %02x\u0022, phdr-\u003espi_mode );\n- ESP_LOGD(TAG, \u0022spi_speed %02x\u0022, phdr-\u003espi_speed );\n- ESP_LOGD(TAG, \u0022spi_size %02x\u0022, phdr-\u003espi_size );\n-\n- const char* str;\n- (void)str;\n- switch ( phdr-\u003espi_speed ) {\n- case ESP_IMAGE_SPI_SPEED_40M:\n- str \u003d \u002240MHz\u0022;\n- break;\n- case ESP_IMAGE_SPI_SPEED_26M:\n- str \u003d \u002226.7MHz\u0022;\n- break;\n- case ESP_IMAGE_SPI_SPEED_20M:\n- str \u003d \u002220MHz\u0022;\n- break;\n- case ESP_IMAGE_SPI_SPEED_80M:\n- str \u003d \u002280MHz\u0022;\n- break;\n- default:\n- str \u003d \u002220MHz\u0022;\n- break;\n- }\n- ESP_LOGI(TAG, \u0022SPI Speed : %s\u0022, str );\n-\n- /* SPI mode could have been set to QIO during boot already,\n- so test the SPI registers not the flash header */\n- uint32_t spi_ctrl \u003d REG_READ(SPI_CTRL_REG(0));\n- if (spi_ctrl \u0026 SPI_FREAD_QIO) {\n- str \u003d \u0022QIO\u0022;\n- } else if (spi_ctrl \u0026 SPI_FREAD_QUAD) {\n- str \u003d \u0022QOUT\u0022;\n- } else if (spi_ctrl \u0026 SPI_FREAD_DIO) {\n- str \u003d \u0022DIO\u0022;\n- } else if (spi_ctrl \u0026 SPI_FREAD_DUAL) {\n- str \u003d \u0022DOUT\u0022;\n- } else if (spi_ctrl \u0026 SPI_FASTRD_MODE) {\n- str \u003d \u0022FAST READ\u0022;\n- } else {\n- str \u003d \u0022SLOW READ\u0022;\n- }\n- ESP_LOGI(TAG, \u0022SPI Mode : %s\u0022, str );\n-\n- switch ( phdr-\u003espi_size ) {\n- case ESP_IMAGE_FLASH_SIZE_1MB:\n- str \u003d \u00221MB\u0022;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_2MB:\n- str \u003d \u00222MB\u0022;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_4MB:\n- str \u003d \u00224MB\u0022;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_8MB:\n- str \u003d \u00228MB\u0022;\n- break;\n- case ESP_IMAGE_FLASH_SIZE_16MB:\n- str \u003d \u002216MB\u0022;\n- break;\n- default:\n- str \u003d \u00222MB\u0022;\n- break;\n- }\n- ESP_LOGI(TAG, \u0022SPI Flash Size : %s\u0022, str );\n-#endif\n-}\n-\n-static void uart_console_configure(void)\n-{\n-#if CONFIG_CONSOLE_UART_NONE\n- ets_install_putc1(NULL);\n- ets_install_putc2(NULL);\n-#else // CONFIG_CONSOLE_UART_NONE\n- const int uart_num \u003d CONFIG_CONSOLE_UART_NUM;\n-\n- uartAttach();\n- ets_install_uart_printf();\n-\n- // ROM bootloader may have put a lot of text into UART0 FIFO.\n- // Wait for it to be printed.\n- uart_tx_wait_idle(0);\n-\n-#if CONFIG_CONSOLE_UART_CUSTOM\n- // Some constants to make the following code less upper-case\n- const int uart_tx_gpio \u003d CONFIG_CONSOLE_UART_TX_GPIO;\n- const int uart_rx_gpio \u003d CONFIG_CONSOLE_UART_RX_GPIO;\n- // Switch to the new UART (this just changes UART number used for\n- // ets_printf in ROM code).\n- uart_tx_switch(uart_num);\n- // If console is attached to UART1 or if non-default pins are used,\n- // need to reconfigure pins using GPIO matrix\n- if (uart_num !\u003d 0 || uart_tx_gpio !\u003d 1 || uart_rx_gpio !\u003d 3) {\n- // Change pin mode for GPIO1/3 from UART to GPIO\n- PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3);\n- PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1);\n- // Route GPIO signals to/from pins\n- // (arrays should be optimized away by the compiler)\n- const uint32_t tx_idx_list[3] \u003d { U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX };\n- const uint32_t rx_idx_list[3] \u003d { U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX };\n- const uint32_t tx_idx \u003d tx_idx_list[uart_num];\n- const uint32_t rx_idx \u003d rx_idx_list[uart_num];\n- gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0);\n- gpio_matrix_in(uart_rx_gpio, rx_idx, 0);\n- }\n-#endif // CONFIG_CONSOLE_UART_CUSTOM\n-\n- // Set configured UART console baud rate\n- const int uart_baud \u003d CONFIG_CONSOLE_UART_BAUDRATE;\n- uart_div_modify(uart_num, (APB_CLK_FREQ \u003c\u003c 4) / uart_baud);\n-\n-#endif // CONFIG_CONSOLE_UART_NONE\n-}\n-\n-/* empty rtc_printf implementation, to work with librtc\n- linking. Can be removed once -lrtc is removed from bootloader's\n- main component.mk.\n-*/\n-int rtc_printf(void)\n-{\n- return 0;\n-}\ndiff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk\ndeleted file mode 100644\nindex 1199005..0000000\n--- a/components/bootloader/src/main/component.mk\n+++ /dev/null\n@@ -1,20 +0,0 @@\n-#\n-# Main bootloader Makefile.\n-#\n-# This is basically the same as a component makefile, but in the case of the bootloader\n-# we pull in bootloader-specific linker arguments.\n-#\n-\n-LINKER_SCRIPTS :\u003d \u005c\n-\tesp32.bootloader.ld \u005c\n-\t$(IDF_PATH)/components/esp32/ld/esp32.rom.ld \u005c\n-\t$(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \u005c\n-\tesp32.bootloader.rom.ld\n-\n-ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH\n-LINKER_SCRIPTS +\u003d $(IDF_PATH)/components/esp32/ld/esp32.rom.spiflash.ld\n-endif\n-\n-COMPONENT_ADD_LDFLAGS :\u003d -L $(COMPONENT_PATH) -lmain $(addprefix -T ,$(LINKER_SCRIPTS))\n-\n-COMPONENT_ADD_LINKER_DEPS :\u003d $(LINKER_SCRIPTS)\ndiff --git a/components/bootloader/src/main/esp32.bootloader.ld b/components/bootloader/src/main/esp32.bootloader.ld\ndeleted file mode 100644\nindex 5004788..0000000\n--- a/components/bootloader/src/main/esp32.bootloader.ld\n+++ /dev/null\n@@ -1,148 +0,0 @@\n-/*\n-Linker file used to link the bootloader.\n-\n-*WARNING* For now this linker dumps everything into IRAM/DRAM. ToDo: move\n-some/most stuff to DROM/IROM.\n-\n-*/\n-\n-\n-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */\n-/* The load addresses are defined later using the AT statements. */\n-MEMORY\n-{\n- /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length\n- of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but\n- are connected to the data port of the CPU and eg allow bytewise access. */\n- dport0_seg (RW) : \torg \u003d 0x3FF00000, len \u003d 0x10\t\t/* IO */\n- iram_seg (RWX) : \torg \u003d 0x40080000, len \u003d 0x400\t\t/* 1k of IRAM used by bootloader functions which need to flush/enable APP CPU cache */ \n- iram_pool_1_seg (RWX) : org \u003d 0x40078000, len \u003d 0x8000 /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, until we enable APP CPU cache */\n- dram_seg (RW) : \torg \u003d 0x3FFF0000, len \u003d 0x10000\t\t/* 64k at the end of DRAM, after ROM bootloader stack */\n-}\n-\n-/* Default entry point: */\n-ENTRY(call_start_cpu0);\n-\n-\n-SECTIONS\n-{\n- .iram1.text :\n- {\n- _init_start \u003d ABSOLUTE(.);\n- *(.UserEnter.literal);\n- *(.UserEnter.text);\n- . \u003d ALIGN (16);\n- *(.entry.text)\n- *(.init.literal)\n- *(.init)\n- _init_end \u003d ABSOLUTE(.);\n-\n-\t /* Code marked as runnning out of IRAM */\n-\t _iram_text_start \u003d ABSOLUTE(.);\n- *(.iram1 .iram1.*)\n-\t _iram_text_end \u003d ABSOLUTE(.);\n- } \u003e iram_seg\n-\n-\n- /* Shared RAM */\n- .dram0.bss (NOLOAD) :\n- {\n- . \u003d ALIGN (8);\n- _bss_start \u003d ABSOLUTE(.);\n- *(.dynsbss)\n- *(.sbss)\n- *(.sbss.*)\n- *(.gnu.linkonce.sb.*)\n- *(.scommon)\n- *(.sbss2)\n- *(.sbss2.*)\n- *(.gnu.linkonce.sb2.*)\n- *(.dynbss)\n- KEEP(*(.bss))\n- *(.bss.*)\n- *(.gnu.linkonce.b.*)\n- *(COMMON)\n- . \u003d ALIGN (8);\n- _bss_end \u003d ABSOLUTE(.);\n- } \u003edram_seg\n-\n-\n- .dram0.data :\n- {\n- _data_start \u003d ABSOLUTE(.);\n- KEEP(*(.data))\n- KEEP(*(.data.*))\n- KEEP(*(.gnu.linkonce.d.*))\n- KEEP(*(.data1))\n- KEEP(*(.sdata))\n- KEEP(*(.sdata.*))\n- KEEP(*(.gnu.linkonce.s.*))\n- KEEP(*(.sdata2))\n- KEEP(*(.sdata2.*))\n- KEEP(*(.gnu.linkonce.s2.*))\n- KEEP(*(.jcr))\n- _data_end \u003d ABSOLUTE(.);\n- } \u003edram_seg\n-\n-\n-\n-\n- .dram0.rodata :\n- {\n- _rodata_start \u003d ABSOLUTE(.);\n- *(.rodata)\n- *(.rodata.*)\n-\t*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */\n- *(.gnu.linkonce.r.*)\n- *(.rodata1)\n- __XT_EXCEPTION_TABLE_ \u003d ABSOLUTE(.);\n- *(.xt_except_table)\n- *(.gcc_except_table)\n- *(.gnu.linkonce.e.*)\n- *(.gnu.version_r)\n- *(.eh_frame)\n- . \u003d (. + 3) \u0026 ~ 3;\n- /* C++ constructor and destructor tables, properly ordered: */\n- __init_array_start \u003d ABSOLUTE(.);\n- KEEP (*crtbegin.o(.ctors))\n- KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))\n- KEEP (*(SORT(.ctors.*)))\n- KEEP (*(.ctors))\n- __init_array_end \u003d ABSOLUTE(.);\n- KEEP (*crtbegin.o(.dtors))\n- KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))\n- KEEP (*(SORT(.dtors.*)))\n- KEEP (*(.dtors))\n- /* C++ exception handlers table: */\n- __XT_EXCEPTION_DESCS_ \u003d ABSOLUTE(.);\n- *(.xt_except_desc)\n- *(.gnu.linkonce.h.*)\n- __XT_EXCEPTION_DESCS_END__ \u003d ABSOLUTE(.);\n- *(.xt_except_desc_end)\n- *(.dynamic)\n- *(.gnu.version_d)\n- _rodata_end \u003d ABSOLUTE(.);\n-\t/* Literals are also RO data. */\n- _lit4_start \u003d ABSOLUTE(.);\n- *(*.lit4)\n- *(.lit4.*)\n- *(.gnu.linkonce.lit4.*)\n- _lit4_end \u003d ABSOLUTE(.);\n- . \u003d ALIGN(4);\n- _heap_start \u003d ABSOLUTE(.);\n- } \u003edram_seg\n-\n- .iram_pool_1.text :\n- {\n- _stext \u003d .;\n- _text_start \u003d ABSOLUTE(.);\n- *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)\n-\t*(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */\n- *(.fini.literal)\n- *(.fini)\n- *(.gnu.version)\n- _text_end \u003d ABSOLUTE(.);\n- _etext \u003d .;\n- } \u003eiram_pool_1_seg\n-\n-}\ndiff --git a/components/bootloader/src/main/esp32.bootloader.rom.ld b/components/bootloader/src/main/esp32.bootloader.rom.ld\ndeleted file mode 100644\nindex 70f83bd..0000000\n--- a/components/bootloader/src/main/esp32.bootloader.rom.ld\n+++ /dev/null\n@@ -1 +0,0 @@\n-PROVIDE ( ets_update_cpu_frequency \u003d 0x40008550 ); /* Updates g_ticks_per_us on the current CPU only; not on the other core */\ndiff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c\ndeleted file mode 100644\nindex cd28829..0000000\n--- a/components/bootloader/src/main/flash_qio_mode.c\n+++ /dev/null\n@@ -1,266 +0,0 @@\n-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n-//\n-// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n-// you may not use this file except in compliance with the License.\n-// You may obtain a copy of the License at\n-\n-// http://www.apache.org/licenses/LICENSE-2.0\n-//\n-// Unless required by applicable law or agreed to in writing, software\n-// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-// See the License for the specific language governing permissions and\n-// limitations under the License.\n-#include \u003cstddef.h\u003e\n-#include \u003cstdint.h\u003e\n-#include \u0022flash_qio_mode.h\u0022\n-#include \u0022esp_log.h\u0022\n-#include \u0022rom/spi_flash.h\u0022\n-#include \u0022rom/efuse.h\u0022\n-#include \u0022soc/spi_struct.h\u0022\n-#include \u0022soc/efuse_reg.h\u0022\n-#include \u0022sdkconfig.h\u0022\n-\n-/* SPI flash controller */\n-#define SPIFLASH SPI1\n-\n-/* SPI commands (actual on-wire commands not SPI controller bitmasks)\n- Suitable for use with the execute_flash_command static function.\n-*/\n-#define CMD_RDID 0x9F\n-#define CMD_WRSR 0x01\n-#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */\n-#define CMD_WREN 0x06\n-#define CMD_WRDI 0x04\n-#define CMD_RDSR 0x05\n-#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */\n-\n-\n-#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */\n-\n-static const char *TAG \u003d \u0022qio_mode\u0022;\n-\n-typedef unsigned (*read_status_fn_t)();\n-typedef void (*write_status_fn_t)(unsigned);\n-\n-typedef struct __attribute__((packed)) {\n- const char *manufacturer;\n- uint8_t mfg_id; /* 8-bit JEDEC manufacturer ID */\n- uint16_t flash_id; /* 16-bit JEDEC flash chip ID */\n- uint16_t id_mask; /* Bits to match on in flash chip ID */\n- read_status_fn_t read_status_fn;\n- write_status_fn_t write_status_fn;\n- uint8_t status_qio_bit;\n-} qio_info_t;\n-\n-/* Read 8 bit status using RDSR command */\n-static unsigned read_status_8b_rdsr();\n-/* Read 8 bit status (second byte) using RDSR2 command */\n-static unsigned read_status_8b_rdsr2();\n-/* read 16 bit status using RDSR \u0026 RDSR2 (low and high bytes) */\n-static unsigned read_status_16b_rdsr_rdsr2();\n-\n-/* Write 8 bit status using WRSR */\n-static void write_status_8b_wrsr(unsigned new_status);\n-/* Write 8 bit status (second byte) using WRSR2 */\n-static void write_status_8b_wrsr2(unsigned new_status);\n-/* Write 16 bit status using WRSR */\n-static void write_status_16b_wrsr(unsigned new_status);\n-\n-/* Array of known flash chips and data to enable Quad I/O mode\n-\n- Manufacturer \u0026 flash ID can be tested by running \u0022esptool.py\n- flash_id\u0022\n-\n- If manufacturer ID matches, and flash ID ORed with flash ID mask\n- matches, enable_qio_mode() will execute \u0022Read Cmd\u0022, test if bit\n- number \u0022QIE Bit\u0022 is set, and if not set it will call \u0022Write Cmd\u0022\n- with this bit set.\n-\n- Searching of this table stops when the first match is found.\n- */\n-const static qio_info_t chip_data[] \u003d {\n-/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */\n- { \u0022MXIC\u0022, 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },\n- { \u0022ISSI\u0022, 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */\n- { \u0022WinBond\u0022, 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },\n-\n- /* Final entry is default entry, if no other IDs have matched.\n-\n- This approach works for chips including:\n- GigaDevice (mfg ID 0xC8, flash IDs including 4016),\n- FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)\n- */\n- { NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },\n-};\n-\n-#define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t))\n-\n-static void enable_qio_mode(read_status_fn_t read_status_fn,\n- write_status_fn_t write_status_fn,\n- uint8_t status_qio_bit);\n-\n-/* Generic function to use the \u0022user command\u0022 SPI controller functionality\n- to send commands to the SPI flash and read the respopnse.\n-\n- The command passed here is always the on-the-wire command given to the SPI flash unit.\n-*/\n-static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);\n-\n-/* dummy_len_plus values defined in ROM for SPI flash configuration */\n-extern uint8_t g_rom_spiflash_dummy_len_plus[];\n-\n-void bootloader_enable_qio_mode(void)\n-{\n- uint32_t raw_flash_id;\n- uint8_t mfg_id;\n- uint16_t flash_id;\n- int i;\n-\n- ESP_LOGD(TAG, \u0022Probing for QIO mode enable...\u0022);\n- esp_rom_spiflash_wait_idle(\u0026g_rom_flashchip);\n-\n- /* Set up some of the SPIFLASH user/ctrl variables which don't change\n- while we're probing using execute_flash_command() */\n- SPIFLASH.ctrl.val \u003d 0;\n- SPIFLASH.user.usr_dummy \u003d 0;\n- SPIFLASH.user.usr_addr \u003d 0;\n- SPIFLASH.user.usr_command \u003d 1;\n- SPIFLASH.user2.usr_command_bitlen \u003d 7;\n-\n- raw_flash_id \u003d execute_flash_command(CMD_RDID, 0, 0, 24);\n- ESP_LOGD(TAG, \u0022Raw SPI flash chip id 0x%x\u0022, raw_flash_id);\n-\n- mfg_id \u003d raw_flash_id \u0026 0xFF;\n- flash_id \u003d (raw_flash_id \u003e\u003e 16) | (raw_flash_id \u0026 0xFF00);\n- ESP_LOGD(TAG, \u0022Manufacturer ID 0x%02x chip ID 0x%04x\u0022, mfg_id, flash_id);\n-\n- for (i \u003d 0; i \u003c NUM_CHIPS-1; i++) {\n- const qio_info_t *chip \u003d \u0026chip_data[i];\n- if (mfg_id \u003d\u003d chip-\u003emfg_id \u0026\u0026 (flash_id \u0026 chip-\u003eid_mask) \u003d\u003d (chip-\u003eflash_id \u0026 chip-\u003eid_mask)) {\n- ESP_LOGI(TAG, \u0022Enabling QIO for flash chip %s\u0022, chip_data[i].manufacturer);\n- break;\n- }\n- }\n-\n- if (i \u003d\u003d NUM_CHIPS - 1) {\n- ESP_LOGI(TAG, \u0022Enabling default flash chip QIO\u0022);\n- }\n-\n- enable_qio_mode(chip_data[i].read_status_fn,\n- chip_data[i].write_status_fn,\n- chip_data[i].status_qio_bit);\n-}\n-\n-static void enable_qio_mode(read_status_fn_t read_status_fn,\n- write_status_fn_t write_status_fn,\n- uint8_t status_qio_bit)\n-{\n- uint32_t status;\n- const uint32_t spiconfig \u003d ets_efuse_get_spiconfig();\n-\n- if (spiconfig !\u003d EFUSE_SPICONFIG_SPI_DEFAULTS \u0026\u0026 spiconfig !\u003d EFUSE_SPICONFIG_HSPI_DEFAULTS) {\n- // spiconfig specifies a custom efuse pin configuration. This config defines all pins -except- WP.\n- //\n- // For now, in this situation we only support Quad I/O mode for ESP32-D2WD where WP pin is known.\n- uint32_t chip_ver \u003d REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_RESERVE);\n- uint32_t pkg_ver \u003d chip_ver \u0026 0x7;\n- const uint32_t PKG_VER_ESP32_D2WD \u003d 2; // TODO: use chip detection API once available\n- if (pkg_ver !\u003d PKG_VER_ESP32_D2WD) {\n- ESP_LOGE(TAG, \u0022Quad I/O is only supported for standard pin numbers or ESP32-D2WD. Falling back to Dual I/O.\u0022);\n- return;\n- }\n- }\n-\n- esp_rom_spiflash_wait_idle(\u0026g_rom_flashchip);\n-\n- status \u003d read_status_fn();\n- ESP_LOGD(TAG, \u0022Initial flash chip status 0x%x\u0022, status);\n-\n- if ((status \u0026 (1\u003c\u003cstatus_qio_bit)) \u003d\u003d 0) {\n- execute_flash_command(CMD_WREN, 0, 0, 0);\n- write_status_fn(status | (1\u003c\u003cstatus_qio_bit));\n-\n- esp_rom_spiflash_wait_idle(\u0026g_rom_flashchip);\n-\n- status \u003d read_status_fn();\n- ESP_LOGD(TAG, \u0022Updated flash chip status 0x%x\u0022, status);\n- if ((status \u0026 (1\u003c\u003cstatus_qio_bit)) \u003d\u003d 0) {\n- ESP_LOGE(TAG, \u0022Failed to set QIE bit, not enabling QIO mode\u0022);\n- return;\n- }\n-\n- } else {\n- ESP_LOGD(TAG, \u0022QIO mode already enabled in flash\u0022);\n- }\n-\n- ESP_LOGD(TAG, \u0022Enabling QIO mode...\u0022);\n-\n- esp_rom_spiflash_read_mode_t mode;\n-#if CONFIG_FLASHMODE_QOUT\n- mode \u003d ESP_ROM_SPIFLASH_QOUT_MODE;\n-#else\n- mode \u003d ESP_ROM_SPIFLASH_QIO_MODE;\n-#endif\n-\n- esp_rom_spiflash_config_readmode(mode);\n-\n- esp_rom_spiflash_select_qio_pins(ESP32_D2WD_WP_GPIO, spiconfig);\n-}\n-\n-static unsigned read_status_8b_rdsr()\n-{\n- return execute_flash_command(CMD_RDSR, 0, 0, 8);\n-}\n-\n-static unsigned read_status_8b_rdsr2()\n-{\n- return execute_flash_command(CMD_RDSR2, 0, 0, 8);\n-}\n-\n-static unsigned read_status_16b_rdsr_rdsr2()\n-{\n- return execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) \u003c\u003c 8);\n-}\n-\n-static void write_status_8b_wrsr(unsigned new_status)\n-{\n- execute_flash_command(CMD_WRSR, new_status, 8, 0);\n-}\n-\n-static void write_status_8b_wrsr2(unsigned new_status)\n-{\n- execute_flash_command(CMD_WRSR2, new_status, 8, 0);\n-}\n-\n-static void write_status_16b_wrsr(unsigned new_status)\n-{\n- execute_flash_command(CMD_WRSR, new_status, 16, 0);\n-}\n-\n-static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)\n-{\n- SPIFLASH.user2.usr_command_value \u003d command;\n- SPIFLASH.user.usr_miso \u003d miso_len \u003e 0;\n- SPIFLASH.miso_dlen.usr_miso_dbitlen \u003d miso_len ? (miso_len - 1) : 0;\n- SPIFLASH.user.usr_mosi \u003d mosi_len \u003e 0;\n- SPIFLASH.mosi_dlen.usr_mosi_dbitlen \u003d mosi_len ? (mosi_len - 1) : 0;\n- SPIFLASH.data_buf[0] \u003d mosi_data;\n-\n- if (g_rom_spiflash_dummy_len_plus[1]) {\n- /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */\n- if (miso_len \u003e 0) {\n- SPIFLASH.user.usr_dummy \u003d 1;\n- SPIFLASH.user1.usr_dummy_cyclelen \u003d g_rom_spiflash_dummy_len_plus[1] - 1;\n- } else {\n- SPIFLASH.user.usr_dummy \u003d 0;\n- SPIFLASH.user1.usr_dummy_cyclelen \u003d 0;\n- }\n- }\n-\n- SPIFLASH.cmd.usr \u003d 1;\n- while(SPIFLASH.cmd.usr !\u003d 0)\n- { }\n-\n- return SPIFLASH.data_buf[0];\n-}\ndiff --git a/components/bootloader/src/main/flash_qio_mode.h b/components/bootloader/src/main/flash_qio_mode.h\ndeleted file mode 100644\nindex 9efa131..0000000\n--- a/components/bootloader/src/main/flash_qio_mode.h\n+++ /dev/null\n@@ -1,29 +0,0 @@\n-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n-//\n-// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n-// you may not use this file except in compliance with the License.\n-// You may obtain a copy of the License at\n-\n-// http://www.apache.org/licenses/LICENSE-2.0\n-//\n-// Unless required by applicable law or agreed to in writing, software\n-// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-// See the License for the specific language governing permissions and\n-// limitations under the License.\n-#pragma once\n-\n-#ifdef __cplusplus\n-extern \u0022C\u0022 {\n-#endif\n-\n-/** @brief Enable Quad I/O mode in bootloader (if configured)\n- *\n- * Queries attached SPI flash ID and sends correct SPI flash\n- * commands to enable QIO or QOUT mode, then enables this mode.\n- */\n-void bootloader_enable_qio_mode(void);\n-\n-#ifdef __cplusplus\n-}\n-#endif\ndiff --git a/components/bootloader/subproject/.gitignore b/components/bootloader/subproject/.gitignore\nnew file mode 100644\nindex 0000000..278a862\n--- /dev/null\n+++ b/components/bootloader/subproject/.gitignore\n@@ -0,0 +1,2 @@\n+build\n+sdkconfig\ndiff --git a/components/bootloader/subproject/Makefile b/components/bootloader/subproject/Makefile\nnew file mode 100644\nindex 0000000..198f40f\n--- /dev/null\n+++ b/components/bootloader/subproject/Makefile\n@@ -0,0 +1,28 @@\n+#\n+# This is a project Makefile. It is assumed the directory this Makefile resides in is a\n+# project subdirectory.\n+#\n+ifeq (\u0022$(MAKELEVEL)\u0022,\u00220\u0022)\n+$(error Bootloader makefile expects to be run as part of 'make bootloader' from a top-level project.)\n+endif\n+\n+PROJECT_NAME :\u003d bootloader\n+\n+COMPONENTS :\u003d esptool_py bootloader_support log spi_flash micro-ecc soc main\n+\n+#We cannot include the esp32 component directly but we need its includes.\n+CFLAGS +\u003d -I $(IDF_PATH)/components/esp32/include\n+\n+# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.\n+#\n+# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op\n+IS_BOOTLOADER_BUILD :\u003d 1\n+export IS_BOOTLOADER_BUILD\n+\n+# BOOTLOADER_BUILD macro is the same, for source file changes\n+CFLAGS +\u003d -D BOOTLOADER_BUILD\u003d1\n+\n+# include the top-level \u0022project\u0022 include directory, for sdkconfig.h\n+CFLAGS +\u003d -I$(BUILD_DIR_BASE)/../include\n+\n+include $(IDF_PATH)/make/project.mk\ndiff --git a/components/bootloader/subproject/main/Makefile.projbuild b/components/bootloader/subproject/main/Makefile.projbuild\nnew file mode 100644\nindex 0000000..c368c68\n--- /dev/null\n+++ b/components/bootloader/subproject/main/Makefile.projbuild\n@@ -0,0 +1,4 @@\n+# Submodules normally added in component.mk, but fully qualified\n+# paths can be added at this level (we need binary librtc to be\n+# available to link bootloader).\n+COMPONENT_SUBMODULES +\u003d $(IDF_PATH)/components/esp32/lib\ndiff --git a/components/bootloader/subproject/main/bootloader_config.h b/components/bootloader/subproject/main/bootloader_config.h\nnew file mode 100644\nindex 0000000..289a9e3\n--- /dev/null\n+++ b/components/bootloader/subproject/main/bootloader_config.h\n@@ -0,0 +1,48 @@\n+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n+//\n+// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+\n+// http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+#ifndef __BOOT_CONFIG_H__\n+#define __BOOT_CONFIG_H__\n+\n+#include \u003cstdint.h\u003e\n+\n+#ifdef __cplusplus\n+extern \u0022C\u0022\n+{\n+#endif\n+\n+#include \u0022esp_flash_data_types.h\u0022\n+#include \u0022soc/soc.h\u0022\n+\n+#define SPI_SEC_SIZE 0x1000\n+\n+#define SPI_ERROR_LOG \u0022spi flash error\u0022\n+\n+#define MAX_OTA_SLOTS 16\n+\n+typedef struct {\n+ esp_partition_pos_t ota_info;\n+ esp_partition_pos_t factory;\n+ esp_partition_pos_t test;\n+ esp_partition_pos_t ota[MAX_OTA_SLOTS];\n+ uint32_t app_count;\n+ uint32_t selected_subtype;\n+} bootloader_state_t;\n+\n+bool flash_encrypt(bootloader_state_t *bs);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* __BOOT_CONFIG_H__ */\ndiff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c\nnew file mode 100644\nindex 0000000..770fd96\n--- /dev/null\n+++ b/components/bootloader/subproject/main/bootloader_start.c\n@@ -0,0 +1,886 @@\n+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n+//\n+// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+//\n+// http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+#include \u003cstring.h\u003e\n+#include \u003cstdint.h\u003e\n+#include \u003climits.h\u003e\n+#include \u003csys/param.h\u003e\n+\n+#include \u0022esp_attr.h\u0022\n+#include \u0022esp_log.h\u0022\n+\n+#include \u0022rom/cache.h\u0022\n+#include \u0022rom/efuse.h\u0022\n+#include \u0022rom/ets_sys.h\u0022\n+#include \u0022rom/spi_flash.h\u0022\n+#include \u0022rom/crc.h\u0022\n+#include \u0022rom/rtc.h\u0022\n+#include \u0022rom/uart.h\u0022\n+#include \u0022rom/gpio.h\u0022\n+#include \u0022rom/secure_boot.h\u0022\n+\n+#include \u0022soc/soc.h\u0022\n+#include \u0022soc/cpu.h\u0022\n+#include \u0022soc/rtc.h\u0022\n+#include \u0022soc/dport_reg.h\u0022\n+#include \u0022soc/io_mux_reg.h\u0022\n+#include \u0022soc/efuse_reg.h\u0022\n+#include \u0022soc/rtc_cntl_reg.h\u0022\n+#include \u0022soc/timer_group_reg.h\u0022\n+#include \u0022soc/gpio_reg.h\u0022\n+#include \u0022soc/gpio_sig_map.h\u0022\n+\n+#include \u0022sdkconfig.h\u0022\n+#include \u0022esp_image_format.h\u0022\n+#include \u0022esp_secure_boot.h\u0022\n+#include \u0022esp_flash_encrypt.h\u0022\n+#include \u0022esp_flash_partitions.h\u0022\n+#include \u0022bootloader_flash.h\u0022\n+#include \u0022bootloader_random.h\u0022\n+#include \u0022bootloader_config.h\u0022\n+\n+#include \u0022flash_qio_mode.h\u0022\n+\n+extern int _bss_start;\n+extern int _bss_end;\n+extern int _data_start;\n+extern int _data_end;\n+\n+static const char* TAG \u003d \u0022boot\u0022;\n+\n+/* Reduce literal size for some generic string literals */\n+#define MAP_MSG \u0022Mapping segment %d as %s\u0022\n+#define MAP_ERR_MSG \u0022Image contains multiple %s segments. Only the last one will be mapped.\u0022\n+\n+void bootloader_main();\n+static void unpack_load_app(const esp_image_metadata_t *data);\n+static void print_flash_info(const esp_image_header_t* pfhdr);\n+static void set_cache_and_start_app(uint32_t drom_addr,\n+ uint32_t drom_load_addr,\n+ uint32_t drom_size,\n+ uint32_t irom_addr,\n+ uint32_t irom_load_addr,\n+ uint32_t irom_size,\n+ uint32_t entry_addr);\n+static void update_flash_config(const esp_image_header_t* pfhdr);\n+static void clock_configure(void);\n+static void uart_console_configure(void);\n+static void wdt_reset_check(void);\n+\n+/*\n+ * We arrive here after the ROM bootloader finished loading this second stage bootloader from flash.\n+ * The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset.\n+ * We do have a stack, so we can do the initialization in C.\n+ */\n+void call_start_cpu0()\n+{\n+ cpu_configure_region_protection();\n+\n+ /* Sanity check that static RAM is after the stack */\n+#ifndef NDEBUG\n+ {\n+ int *sp \u003d get_sp();\n+ assert(\u0026_bss_start \u003c\u003d \u0026_bss_end);\n+ assert(\u0026_data_start \u003c\u003d \u0026_data_end);\n+ assert(sp \u003c \u0026_bss_start);\n+ assert(sp \u003c \u0026_data_start);\n+ }\n+#endif\n+\n+ //Clear bss\n+ memset(\u0026_bss_start, 0, (\u0026_bss_end - \u0026_bss_start) * sizeof(_bss_start));\n+\n+ /* completely reset MMU for both CPUs\n+ (in case serial bootloader was running) */\n+ Cache_Read_Disable(0);\n+ Cache_Read_Disable(1);\n+ Cache_Flush(0);\n+ Cache_Flush(1);\n+ mmu_init(0);\n+ DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);\n+ mmu_init(1);\n+ DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);\n+ /* (above steps probably unnecessary for most serial bootloader\n+ usage, all that's absolutely needed is that we unmask DROM0\n+ cache on the following two lines - normal ROM boot exits with\n+ DROM0 cache unmasked, but serial bootloader exits with it\n+ masked. However can't hurt to be thorough and reset\n+ everything.)\n+\n+ The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are\n+ necessary to work around a hardware bug.\n+ */\n+ DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);\n+ DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);\n+\n+ bootloader_main();\n+}\n+\n+\n+/** @brief Load partition table\n+ *\n+ * Parse partition table, get useful data such as location of\n+ * OTA data partition, factory app partition, and test app partition.\n+ *\n+ * @param bs bootloader state structure used to save read data\n+ * @return return true if the partition table was succesfully loaded and MD5 checksum is valid.\n+ */\n+bool load_partition_table(bootloader_state_t* bs)\n+{\n+ const esp_partition_info_t *partitions;\n+ const int ESP_PARTITION_TABLE_DATA_LEN \u003d 0xC00; /* length of actual data (signature is appended to this) */\n+ char *partition_usage;\n+ esp_err_t err;\n+ int num_partitions;\n+\n+#ifdef CONFIG_SECURE_BOOT_ENABLED\n+ if(esp_secure_boot_enabled()) {\n+ ESP_LOGI(TAG, \u0022Verifying partition table signature...\u0022);\n+ err \u003d esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);\n+ if (err !\u003d ESP_OK) {\n+ ESP_LOGE(TAG, \u0022Failed to verify partition table signature.\u0022);\n+ return false;\n+ }\n+ ESP_LOGD(TAG, \u0022Partition table signature verified\u0022);\n+ }\n+#endif\n+\n+ partitions \u003d bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);\n+ if (!partitions) {\n+ ESP_LOGE(TAG, \u0022bootloader_mmap(0x%x, 0x%x) failed\u0022, ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);\n+ return false;\n+ }\n+ ESP_LOGD(TAG, \u0022mapped partition table 0x%x at 0x%x\u0022, ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);\n+\n+ err \u003d esp_partition_table_basic_verify(partitions, true, \u0026num_partitions);\n+ if (err !\u003d ESP_OK) {\n+ ESP_LOGE(TAG, \u0022Failed to verify partition table\u0022);\n+ return false;\n+ }\n+\n+ ESP_LOGI(TAG, \u0022Partition Table:\u0022);\n+ ESP_LOGI(TAG, \u0022## Label Usage Type ST Offset Length\u0022);\n+\n+ for(int i \u003d 0; i \u003c num_partitions; i++) {\n+ const esp_partition_info_t *partition \u003d \u0026partitions[i];\n+ ESP_LOGD(TAG, \u0022load partition table entry 0x%x\u0022, (intptr_t)partition);\n+ ESP_LOGD(TAG, \u0022type\u003d%x subtype\u003d%x\u0022, partition-\u003etype, partition-\u003esubtype);\n+ partition_usage \u003d \u0022unknown\u0022;\n+\n+ /* valid partition table */\n+ switch(partition-\u003etype) {\n+ case PART_TYPE_APP: /* app partition */\n+ switch(partition-\u003esubtype) {\n+ case PART_SUBTYPE_FACTORY: /* factory binary */\n+ bs-\u003efactory \u003d partition-\u003epos;\n+ partition_usage \u003d \u0022factory app\u0022;\n+ break;\n+ case PART_SUBTYPE_TEST: /* test binary */\n+ bs-\u003etest \u003d partition-\u003epos;\n+ partition_usage \u003d \u0022test app\u0022;\n+ break;\n+ default:\n+ /* OTA binary */\n+ if ((partition-\u003esubtype \u0026 ~PART_SUBTYPE_OTA_MASK) \u003d\u003d PART_SUBTYPE_OTA_FLAG) {\n+ bs-\u003eota[partition-\u003esubtype \u0026 PART_SUBTYPE_OTA_MASK] \u003d partition-\u003epos;\n+ ++bs-\u003eapp_count;\n+ partition_usage \u003d \u0022OTA app\u0022;\n+ }\n+ else {\n+ partition_usage \u003d \u0022Unknown app\u0022;\n+ }\n+ break;\n+ }\n+ break; /* PART_TYPE_APP */\n+ case PART_TYPE_DATA: /* data partition */\n+ switch(partition-\u003esubtype) {\n+ case PART_SUBTYPE_DATA_OTA: /* ota data */\n+ bs-\u003eota_info \u003d partition-\u003epos;\n+ partition_usage \u003d \u0022OTA data\u0022;\n+ break;\n+ case PART_SUBTYPE_DATA_RF:\n+ partition_usage \u003d \u0022RF data\u0022;\n+ break;\n+ case PART_SUBTYPE_DATA_WIFI:\n+ partition_usage \u003d \u0022WiFi data\u0022;\n+ break;\n+ default:\n+ partition_usage \u003d \u0022Unknown data\u0022;\n+ break;\n+ }\n+ break; /* PARTITION_USAGE_DATA */\n+ default: /* other partition type */\n+ break;\n+ }\n+\n+ /* print partition type info */\n+ ESP_LOGI(TAG, \u0022%2d %-16s %-16s %02x %02x %08x %08x\u0022, i, partition-\u003elabel, partition_usage,\n+ partition-\u003etype, partition-\u003esubtype,\n+ partition-\u003epos.offset, partition-\u003epos.size);\n+ }\n+\n+ bootloader_munmap(partitions);\n+\n+ ESP_LOGI(TAG,\u0022End of partition table\u0022);\n+ return true;\n+}\n+\n+static uint32_t ota_select_crc(const esp_ota_select_entry_t *s)\n+{\n+ return crc32_le(UINT32_MAX, (uint8_t*)\u0026s-\u003eota_seq, 4);\n+}\n+\n+static bool ota_select_valid(const esp_ota_select_entry_t *s)\n+{\n+ return s-\u003eota_seq !\u003d UINT32_MAX \u0026\u0026 s-\u003ecrc \u003d\u003d ota_select_crc(s);\n+}\n+\n+/* indexes used by index_to_partition are the OTA index\n+ number, or these special constants */\n+#define FACTORY_INDEX (-1)\n+#define TEST_APP_INDEX (-2)\n+#define INVALID_INDEX (-99)\n+\n+/* Given a partition index, return the partition position data from the bootloader_state_t structure */\n+static esp_partition_pos_t index_to_partition(const bootloader_state_t *bs, int index)\n+{\n+ if (index \u003d\u003d FACTORY_INDEX) {\n+ return bs-\u003efactory;\n+ }\n+\n+ if (index \u003d\u003d TEST_APP_INDEX) {\n+ return bs-\u003etest;\n+ }\n+\n+ if (index \u003e\u003d 0 \u0026\u0026 index \u003c MAX_OTA_SLOTS) {\n+ return bs-\u003eota[index % bs-\u003eapp_count];\n+ }\n+\n+ esp_partition_pos_t invalid \u003d { 0 };\n+ return invalid;\n+}\n+\n+static void log_invalid_app_partition(int index)\n+{\n+ switch(index) {\n+ case FACTORY_INDEX:\n+ ESP_LOGE(TAG, \u0022Factory app partition is not bootable\u0022);\n+ break;\n+ case TEST_APP_INDEX:\n+ ESP_LOGE(TAG, \u0022Factory test app partition is not bootable\u0022);\n+ break;\n+ default:\n+ ESP_LOGE(TAG, \u0022OTA app partition slot %d is not bootable\u0022, index);\n+ break;\n+ }\n+}\n+\n+\n+/* Return the index of the selected boot partition.\n+\n+ This is the preferred boot partition, as determined by the partition table \u0026 OTA data.\n+\n+ This partition will only be booted if it contains a valid app image, otherwise load_boot_image() will search\n+ for a valid partition using this selection as the starting point.\n+*/\n+static int get_selected_boot_partition(const bootloader_state_t *bs)\n+{\n+ esp_ota_select_entry_t sa,sb;\n+ const esp_ota_select_entry_t *ota_select_map;\n+\n+ if (bs-\u003eota_info.offset !\u003d 0) {\n+ // partition table has OTA data partition\n+ if (bs-\u003eota_info.size \u003c 2 * SPI_SEC_SIZE) {\n+ ESP_LOGE(TAG, \u0022ota_info partition size %d is too small (minimum %d bytes)\u0022, bs-\u003eota_info.size, sizeof(esp_ota_select_entry_t));\n+ return INVALID_INDEX; // can't proceed\n+ }\n+\n+ ESP_LOGD(TAG, \u0022OTA data offset 0x%x\u0022, bs-\u003eota_info.offset);\n+ ota_select_map \u003d bootloader_mmap(bs-\u003eota_info.offset, bs-\u003eota_info.size);\n+ if (!ota_select_map) {\n+ ESP_LOGE(TAG, \u0022bootloader_mmap(0x%x, 0x%x) failed\u0022, bs-\u003eota_info.offset, bs-\u003eota_info.size);\n+ return INVALID_INDEX; // can't proceed\n+ }\n+ memcpy(\u0026sa, ota_select_map, sizeof(esp_ota_select_entry_t));\n+ memcpy(\u0026sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));\n+ bootloader_munmap(ota_select_map);\n+\n+ ESP_LOGD(TAG, \u0022OTA sequence values A 0x%08x B 0x%08x\u0022, sa.ota_seq, sb.ota_seq);\n+ if(sa.ota_seq \u003d\u003d UINT32_MAX \u0026\u0026 sb.ota_seq \u003d\u003d UINT32_MAX) {\n+ ESP_LOGD(TAG, \u0022OTA sequence numbers both empty (all-0xFF)\u0022);\n+ if (bs-\u003efactory.offset !\u003d 0) {\n+ ESP_LOGI(TAG, \u0022Defaulting to factory image\u0022);\n+ return FACTORY_INDEX;\n+ } else {\n+ ESP_LOGI(TAG, \u0022No factory image, trying OTA 0\u0022);\n+ return 0;\n+ }\n+ } else {\n+ if(ota_select_valid(\u0026sa) \u0026\u0026 ota_select_valid(\u0026sb)) {\n+ ESP_LOGD(TAG, \u0022Both OTA sequence valid, using OTA slot %d\u0022, MAX(sa.ota_seq, sb.ota_seq)-1);\n+ return MAX(sa.ota_seq, sb.ota_seq) - 1;\n+ } else if(ota_select_valid(\u0026sa)) {\n+ ESP_LOGD(TAG, \u0022Only OTA sequence A is valid, using OTA slot %d\u0022, sa.ota_seq - 1);\n+ return sa.ota_seq - 1;\n+ } else if(ota_select_valid(\u0026sb)) {\n+ ESP_LOGD(TAG, \u0022Only OTA sequence B is valid, using OTA slot %d\u0022, sb.ota_seq - 1);\n+ return sb.ota_seq - 1;\n+ } else if (bs-\u003efactory.offset !\u003d 0) {\n+ ESP_LOGE(TAG, \u0022ota data partition invalid, falling back to factory\u0022);\n+ return FACTORY_INDEX;\n+ } else {\n+ ESP_LOGE(TAG, \u0022ota data partition invalid and no factory, will try all partitions\u0022);\n+ return FACTORY_INDEX;\n+ }\n+ }\n+ }\n+\n+ // otherwise, start from factory app partition and let the search logic\n+ // proceed from there\n+ return FACTORY_INDEX;\n+}\n+\n+/* Return true if a partition has a valid app image that was successfully loaded */\n+static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_metadata_t *data)\n+{\n+ if (partition-\u003esize \u003d\u003d 0) {\n+ ESP_LOGD(TAG, \u0022Can't boot from zero-length partition\u0022);\n+ return false;\n+ }\n+\n+ if (esp_image_load(ESP_IMAGE_LOAD, partition, data) \u003d\u003d ESP_OK) {\n+ ESP_LOGI(TAG, \u0022Loaded app from partition at offset 0x%x\u0022,\n+ partition-\u003eoffset);\n+ return true;\n+ }\n+\n+ return false;\n+}\n+\n+/* Load the app for booting. Start from partition 'start_index', if not bootable then work backwards to FACTORY_INDEX\n+ * (ie try any OTA slots in descending order and then the factory partition).\n+ *\n+ * If still nothing, start from 'start_index + 1' and work up to highest numbered OTA partition.\n+ *\n+ * If still nothing, try TEST_APP_INDEX\n+ *\n+ * Returns true on success, false if there's no bootable app in the partition table.\n+ */\n+static bool load_boot_image(const bootloader_state_t *bs, int start_index, esp_image_metadata_t *result)\n+{\n+ int index \u003d start_index;\n+ esp_partition_pos_t part;\n+\n+ /* work backwards from start_index, down to the factory app */\n+ do {\n+ ESP_LOGD(TAG, \u0022Trying partition index %d...\u0022, index);\n+ part \u003d index_to_partition(bs, index);\n+ ESP_LOGD(TAG, \u0022part offs 0x%x size 0x%x\u0022, part.offset, part.size);\n+ if (try_load_partition(\u0026part, result)) {\n+ return true;\n+ }\n+ if (part.size \u003e 0) {\n+ log_invalid_app_partition(index);\n+ }\n+ index--;\n+ } while(index \u003e\u003d FACTORY_INDEX);\n+\n+ /* failing that work forwards from start_index, try valid OTA slots */\n+ index \u003d start_index + 1;\n+ while (index \u003c bs-\u003eapp_count) {\n+ ESP_LOGD(TAG, \u0022Trying partition index %d...\u0022, index);\n+ part \u003d index_to_partition(bs, index);\n+ if (try_load_partition(\u0026part, result)) {\n+ return true;\n+ }\n+ log_invalid_app_partition(index);\n+ index++;\n+ }\n+\n+ if (try_load_partition(\u0026bs-\u003etest, result)) {\n+ ESP_LOGW(TAG, \u0022Falling back to test app as only bootable partition\u0022);\n+ return true;\n+ }\n+\n+ ESP_LOGE(TAG, \u0022No bootable app partitions in the partition table\u0022);\n+ bzero(result, sizeof(esp_image_metadata_t));\n+ return false;\n+}\n+\n+\n+/**\n+ * @function : bootloader_main\n+ * @description: entry function of 2nd bootloader\n+ *\n+ * @inputs: void\n+ */\n+\n+void bootloader_main()\n+{\n+ clock_configure();\n+ uart_console_configure();\n+ wdt_reset_check();\n+ ESP_LOGI(TAG, \u0022ESP-IDF %s 2nd stage bootloader\u0022, IDF_VER);\n+#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)\n+ esp_err_t err;\n+#endif\n+ esp_image_header_t fhdr;\n+ bootloader_state_t bs \u003d { 0 };\n+\n+ ESP_LOGI(TAG, \u0022compile time \u0022 __TIME__ );\n+ ets_set_appcpu_boot_addr(0);\n+\n+ /* disable watch dog here */\n+ REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );\n+ REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );\n+\n+#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH\n+ const uint32_t spiconfig \u003d ets_efuse_get_spiconfig();\n+ if(spiconfig !\u003d EFUSE_SPICONFIG_SPI_DEFAULTS \u0026\u0026 spiconfig !\u003d EFUSE_SPICONFIG_HSPI_DEFAULTS) {\n+ ESP_LOGE(TAG, \u0022SPI flash pins are overridden. \u005c\u0022Enable SPI flash ROM driver patched functions\u005c\u0022 must be enabled in menuconfig\u0022);\n+ return;\n+ }\n+#endif\n+\n+ esp_rom_spiflash_unlock();\n+\n+ ESP_LOGI(TAG, \u0022Enabling RNG early entropy source...\u0022);\n+ bootloader_random_enable();\n+\n+#if CONFIG_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT\n+ bootloader_enable_qio_mode();\n+#endif\n+\n+ if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, \u0026fhdr,\n+ sizeof(esp_image_header_t), true) !\u003d ESP_OK) {\n+ ESP_LOGE(TAG, \u0022failed to load bootloader header!\u0022);\n+ return;\n+ }\n+\n+ print_flash_info(\u0026fhdr);\n+\n+ update_flash_config(\u0026fhdr);\n+\n+ if (!load_partition_table(\u0026bs)) {\n+ ESP_LOGE(TAG, \u0022load partition table error!\u0022);\n+ return;\n+ }\n+\n+ int boot_index \u003d get_selected_boot_partition(\u0026bs);\n+ if (boot_index \u003d\u003d INVALID_INDEX) {\n+ return; // Unrecoverable failure (not due to corrupt ota data or bad partition contents)\n+ }\n+ // Start from the default, look for the first bootable partition\n+ esp_image_metadata_t image_data;\n+ if (!load_boot_image(\u0026bs, boot_index, \u0026image_data)) {\n+ return;\n+ }\n+\n+#ifdef CONFIG_SECURE_BOOT_ENABLED\n+ /* Generate secure digest from this bootloader to protect future\n+ modifications */\n+ ESP_LOGI(TAG, \u0022Checking secure boot...\u0022);\n+ err \u003d esp_secure_boot_permanently_enable();\n+ if (err !\u003d ESP_OK) {\n+ ESP_LOGE(TAG, \u0022Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.\u0022, err);\n+ /* Allow booting to continue, as the failure is probably\n+ due to user-configured EFUSEs for testing...\n+ */\n+ }\n+#endif\n+\n+#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED\n+ /* encrypt flash */\n+ ESP_LOGI(TAG, \u0022Checking flash encryption...\u0022);\n+ bool flash_encryption_enabled \u003d esp_flash_encryption_enabled();\n+ err \u003d esp_flash_encrypt_check_and_update();\n+ if (err !\u003d ESP_OK) {\n+ ESP_LOGE(TAG, \u0022Flash encryption check failed (%d).\u0022, err);\n+ return;\n+ }\n+\n+ if (!flash_encryption_enabled \u0026\u0026 esp_flash_encryption_enabled()) {\n+ /* Flash encryption was just enabled for the first time,\n+ so issue a system reset to ensure flash encryption\n+ cache resets properly */\n+ ESP_LOGI(TAG, \u0022Resetting with flash encryption enabled...\u0022);\n+ REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);\n+ return;\n+ }\n+#endif\n+\n+ ESP_LOGI(TAG, \u0022Disabling RNG early entropy source...\u0022);\n+ bootloader_random_disable();\n+\n+ // copy loaded segments to RAM, set up caches for mapped segments, and start application\n+ unpack_load_app(\u0026image_data);\n+}\n+\n+static void unpack_load_app(const esp_image_metadata_t* data)\n+{\n+ uint32_t drom_addr \u003d 0;\n+ uint32_t drom_load_addr \u003d 0;\n+ uint32_t drom_size \u003d 0;\n+ uint32_t irom_addr \u003d 0;\n+ uint32_t irom_load_addr \u003d 0;\n+ uint32_t irom_size \u003d 0;\n+\n+ // Find DROM \u0026 IROM addresses, to configure cache mappings\n+ for (int i \u003d 0; i \u003c data-\u003eimage.segment_count; i++) {\n+ const esp_image_segment_header_t *header \u003d \u0026data-\u003esegments[i];\n+ if (header-\u003eload_addr \u003e\u003d SOC_IROM_LOW \u0026\u0026 header-\u003eload_addr \u003c SOC_IROM_HIGH) {\n+ if (drom_addr !\u003d 0) {\n+ ESP_LOGE(TAG, MAP_ERR_MSG, \u0022DROM\u0022);\n+ } else {\n+ ESP_LOGD(TAG, \u0022Mapping segment %d as %s\u0022, i, \u0022DROM\u0022);\n+ }\n+ drom_addr \u003d data-\u003esegment_data[i];\n+ drom_load_addr \u003d header-\u003eload_addr;\n+ drom_size \u003d header-\u003edata_len;\n+ }\n+ if (header-\u003eload_addr \u003e\u003d SOC_DROM_LOW \u0026\u0026 header-\u003eload_addr \u003c SOC_DROM_HIGH) {\n+ if (irom_addr !\u003d 0) {\n+ ESP_LOGE(TAG, MAP_ERR_MSG, \u0022IROM\u0022);\n+ } else {\n+ ESP_LOGD(TAG, \u0022Mapping segment %d as %s\u0022, i, \u0022IROM\u0022);\n+ }\n+ irom_addr \u003d data-\u003esegment_data[i];\n+ irom_load_addr \u003d header-\u003eload_addr;\n+ irom_size \u003d header-\u003edata_len;\n+ }\n+ }\n+\n+ ESP_LOGD(TAG, \u0022calling set_cache_and_start_app\u0022);\n+ set_cache_and_start_app(drom_addr,\n+ drom_load_addr,\n+ drom_size,\n+ irom_addr,\n+ irom_load_addr,\n+ irom_size,\n+ data-\u003eimage.entry_addr);\n+}\n+\n+static void set_cache_and_start_app(\n+ uint32_t drom_addr,\n+ uint32_t drom_load_addr,\n+ uint32_t drom_size,\n+ uint32_t irom_addr,\n+ uint32_t irom_load_addr,\n+ uint32_t irom_size,\n+ uint32_t entry_addr)\n+{\n+ ESP_LOGD(TAG, \u0022configure drom and irom and start\u0022);\n+ Cache_Read_Disable( 0 );\n+ Cache_Flush( 0 );\n+\n+ /* Clear the MMU entries that are already set up,\n+ so the new app only has the mappings it creates.\n+ */\n+ for (int i \u003d 0; i \u003c DPORT_FLASH_MMU_TABLE_SIZE; i++) {\n+ DPORT_PRO_FLASH_MMU_TABLE[i] \u003d DPORT_FLASH_MMU_TABLE_INVALID_VAL;\n+ }\n+\n+ uint32_t drom_page_count \u003d (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k\n+ ESP_LOGV(TAG, \u0022d mmu set paddr\u003d%08x vaddr\u003d%08x size\u003d%d n\u003d%d\u0022, drom_addr \u0026 0xffff0000, drom_load_addr \u0026 0xffff0000, drom_size, drom_page_count );\n+ int rc \u003d cache_flash_mmu_set( 0, 0, drom_load_addr \u0026 0xffff0000, drom_addr \u0026 0xffff0000, 64, drom_page_count );\n+ ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n+ rc \u003d cache_flash_mmu_set( 1, 0, drom_load_addr \u0026 0xffff0000, drom_addr \u0026 0xffff0000, 64, drom_page_count );\n+ ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n+ uint32_t irom_page_count \u003d (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k\n+ ESP_LOGV(TAG, \u0022i mmu set paddr\u003d%08x vaddr\u003d%08x size\u003d%d n\u003d%d\u0022, irom_addr \u0026 0xffff0000, irom_load_addr \u0026 0xffff0000, irom_size, irom_page_count );\n+ rc \u003d cache_flash_mmu_set( 0, 0, irom_load_addr \u0026 0xffff0000, irom_addr \u0026 0xffff0000, 64, irom_page_count );\n+ ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n+ rc \u003d cache_flash_mmu_set( 1, 0, irom_load_addr \u0026 0xffff0000, irom_addr \u0026 0xffff0000, 64, irom_page_count );\n+ ESP_LOGV(TAG, \u0022rc\u003d%d\u0022, rc );\n+ DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 \u0026 0) | (DPORT_PRO_CACHE_MASK_IROM0 \u0026 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );\n+ DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 \u0026 0) | (DPORT_APP_CACHE_MASK_IROM0 \u0026 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );\n+ Cache_Read_Enable( 0 );\n+\n+ // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)\n+\n+ ESP_LOGD(TAG, \u0022start: 0x%08x\u0022, entry_addr);\n+ typedef void (*entry_t)(void);\n+ entry_t entry \u003d ((entry_t) entry_addr);\n+\n+ // TODO: we have used quite a bit of stack at this point.\n+ // use \u0022movsp\u0022 instruction to reset stack back to where ROM stack starts.\n+ (*entry)();\n+}\n+\n+static void update_flash_config(const esp_image_header_t* pfhdr)\n+{\n+ uint32_t size;\n+ switch(pfhdr-\u003espi_size) {\n+ case ESP_IMAGE_FLASH_SIZE_1MB:\n+ size \u003d 1;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_2MB:\n+ size \u003d 2;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_4MB:\n+ size \u003d 4;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_8MB:\n+ size \u003d 8;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_16MB:\n+ size \u003d 16;\n+ break;\n+ default:\n+ size \u003d 2;\n+ }\n+ Cache_Read_Disable( 0 );\n+ // Set flash chip size\n+ esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);\n+ // TODO: set mode\n+ // TODO: set frequency\n+ Cache_Flush(0);\n+ Cache_Read_Enable( 0 );\n+}\n+\n+static void print_flash_info(const esp_image_header_t* phdr)\n+{\n+#if (BOOT_LOG_LEVEL \u003e\u003d BOOT_LOG_LEVEL_NOTICE)\n+\n+ ESP_LOGD(TAG, \u0022magic %02x\u0022, phdr-\u003emagic );\n+ ESP_LOGD(TAG, \u0022segments %02x\u0022, phdr-\u003esegment_count );\n+ ESP_LOGD(TAG, \u0022spi_mode %02x\u0022, phdr-\u003espi_mode );\n+ ESP_LOGD(TAG, \u0022spi_speed %02x\u0022, phdr-\u003espi_speed );\n+ ESP_LOGD(TAG, \u0022spi_size %02x\u0022, phdr-\u003espi_size );\n+\n+ const char* str;\n+ switch ( phdr-\u003espi_speed ) {\n+ case ESP_IMAGE_SPI_SPEED_40M:\n+ str \u003d \u002240MHz\u0022;\n+ break;\n+ case ESP_IMAGE_SPI_SPEED_26M:\n+ str \u003d \u002226.7MHz\u0022;\n+ break;\n+ case ESP_IMAGE_SPI_SPEED_20M:\n+ str \u003d \u002220MHz\u0022;\n+ break;\n+ case ESP_IMAGE_SPI_SPEED_80M:\n+ str \u003d \u002280MHz\u0022;\n+ break;\n+ default:\n+ str \u003d \u002220MHz\u0022;\n+ break;\n+ }\n+ ESP_LOGI(TAG, \u0022SPI Speed : %s\u0022, str );\n+\n+ /* SPI mode could have been set to QIO during boot already,\n+ so test the SPI registers not the flash header */\n+ uint32_t spi_ctrl \u003d REG_READ(SPI_CTRL_REG(0));\n+ if (spi_ctrl \u0026 SPI_FREAD_QIO) {\n+ str \u003d \u0022QIO\u0022;\n+ } else if (spi_ctrl \u0026 SPI_FREAD_QUAD) {\n+ str \u003d \u0022QOUT\u0022;\n+ } else if (spi_ctrl \u0026 SPI_FREAD_DIO) {\n+ str \u003d \u0022DIO\u0022;\n+ } else if (spi_ctrl \u0026 SPI_FREAD_DUAL) {\n+ str \u003d \u0022DOUT\u0022;\n+ } else if (spi_ctrl \u0026 SPI_FASTRD_MODE) {\n+ str \u003d \u0022FAST READ\u0022;\n+ } else {\n+ str \u003d \u0022SLOW READ\u0022;\n+ }\n+ ESP_LOGI(TAG, \u0022SPI Mode : %s\u0022, str );\n+\n+ switch ( phdr-\u003espi_size ) {\n+ case ESP_IMAGE_FLASH_SIZE_1MB:\n+ str \u003d \u00221MB\u0022;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_2MB:\n+ str \u003d \u00222MB\u0022;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_4MB:\n+ str \u003d \u00224MB\u0022;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_8MB:\n+ str \u003d \u00228MB\u0022;\n+ break;\n+ case ESP_IMAGE_FLASH_SIZE_16MB:\n+ str \u003d \u002216MB\u0022;\n+ break;\n+ default:\n+ str \u003d \u00222MB\u0022;\n+ break;\n+ }\n+ ESP_LOGI(TAG, \u0022SPI Flash Size : %s\u0022, str );\n+#endif\n+}\n+\n+\n+static void clock_configure(void)\n+{\n+ /* Set CPU to 80MHz. Keep other clocks unmodified. */\n+ rtc_cpu_freq_t cpu_freq \u003d RTC_CPU_FREQ_80M;\n+\n+ /* On ESP32 rev 0, switching to 80MHz if clock was previously set to\n+ * 240 MHz may cause the chip to lock up (see section 3.5 of the errata\n+ * document). For rev. 0, switch to 240 instead if it was chosen in\n+ * menuconfig.\n+ */\n+ uint32_t chip_ver_reg \u003d REG_READ(EFUSE_BLK0_RDATA3_REG);\n+ if ((chip_ver_reg \u0026 EFUSE_RD_CHIP_VER_REV1_M) \u003d\u003d 0 \u0026\u0026\n+ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ \u003d\u003d 240) {\n+ cpu_freq \u003d RTC_CPU_FREQ_240M;\n+ }\n+\n+ uart_tx_wait_idle(0);\n+ rtc_clk_config_t clk_cfg \u003d RTC_CLK_CONFIG_DEFAULT();\n+ clk_cfg.xtal_freq \u003d CONFIG_ESP32_XTAL_FREQ;\n+ clk_cfg.cpu_freq \u003d cpu_freq;\n+ clk_cfg.slow_freq \u003d rtc_clk_slow_freq_get();\n+ clk_cfg.fast_freq \u003d rtc_clk_fast_freq_get();\n+ rtc_clk_init(clk_cfg);\n+ /* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable\n+ * it here. Usually it needs some time to start up, so we amortize at least\n+ * part of the start up time by enabling 32k XTAL early.\n+ * App startup code will wait until the oscillator has started up.\n+ */\n+#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL\n+ if (!rtc_clk_32k_enabled()) {\n+ rtc_clk_32k_bootstrap();\n+ }\n+#endif\n+}\n+\n+static void uart_console_configure(void)\n+{\n+#if CONFIG_CONSOLE_UART_NONE\n+ ets_install_putc1(NULL);\n+ ets_install_putc2(NULL);\n+#else // CONFIG_CONSOLE_UART_NONE\n+ const int uart_num \u003d CONFIG_CONSOLE_UART_NUM;\n+\n+ uartAttach();\n+ ets_install_uart_printf();\n+\n+ // ROM bootloader may have put a lot of text into UART0 FIFO.\n+ // Wait for it to be printed.\n+ uart_tx_wait_idle(0);\n+\n+#if CONFIG_CONSOLE_UART_CUSTOM\n+ // Some constants to make the following code less upper-case\n+ const int uart_tx_gpio \u003d CONFIG_CONSOLE_UART_TX_GPIO;\n+ const int uart_rx_gpio \u003d CONFIG_CONSOLE_UART_RX_GPIO;\n+ // Switch to the new UART (this just changes UART number used for\n+ // ets_printf in ROM code).\n+ uart_tx_switch(uart_num);\n+ // If console is attached to UART1 or if non-default pins are used,\n+ // need to reconfigure pins using GPIO matrix\n+ if (uart_num !\u003d 0 || uart_tx_gpio !\u003d 1 || uart_rx_gpio !\u003d 3) {\n+ // Change pin mode for GPIO1/3 from UART to GPIO\n+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3);\n+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1);\n+ // Route GPIO signals to/from pins\n+ // (arrays should be optimized away by the compiler)\n+ const uint32_t tx_idx_list[3] \u003d { U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX };\n+ const uint32_t rx_idx_list[3] \u003d { U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX };\n+ const uint32_t tx_idx \u003d tx_idx_list[uart_num];\n+ const uint32_t rx_idx \u003d rx_idx_list[uart_num];\n+ gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0);\n+ gpio_matrix_in(uart_rx_gpio, rx_idx, 0);\n+ }\n+#endif // CONFIG_CONSOLE_UART_CUSTOM\n+\n+ // Set configured UART console baud rate\n+ const int uart_baud \u003d CONFIG_CONSOLE_UART_BAUDRATE;\n+ uart_div_modify(uart_num, (rtc_clk_apb_freq_get() \u003c\u003c 4) / uart_baud);\n+\n+#endif // CONFIG_CONSOLE_UART_NONE\n+}\n+\n+static void wdt_reset_cpu0_info_enable(void)\n+{\n+ //We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1.\n+ DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE);\n+ DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE);\n+}\n+\n+static void wdt_reset_info_dump(int cpu)\n+{\n+ uint32_t inst \u003d 0, pid \u003d 0, stat \u003d 0, data \u003d 0, pc \u003d 0,\n+ lsstat \u003d 0, lsaddr \u003d 0, lsdata \u003d 0, dstat \u003d 0;\n+ char *cpu_name \u003d cpu ? \u0022APP\u0022 : \u0022PRO\u0022;\n+\n+ if (cpu \u003d\u003d 0) {\n+ stat \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_STATUS_REG);\n+ pid \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PID_REG);\n+ inst \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGINST_REG);\n+ dstat \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGSTATUS_REG);\n+ data \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGDATA_REG);\n+ pc \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGPC_REG);\n+ lsstat \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0STAT_REG);\n+ lsaddr \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0ADDR_REG);\n+ lsdata \u003d DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0DATA_REG);\n+\n+ } else {\n+ stat \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_STATUS_REG);\n+ pid \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PID_REG);\n+ inst \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGINST_REG);\n+ dstat \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGSTATUS_REG);\n+ data \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGDATA_REG);\n+ pc \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGPC_REG);\n+ lsstat \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0STAT_REG);\n+ lsaddr \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0ADDR_REG);\n+ lsdata \u003d DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0DATA_REG);\n+ }\n+ if (DPORT_RECORD_PDEBUGINST_SZ(inst) \u003d\u003d 0 \u0026\u0026\n+ DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) \u003d\u003d DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) {\n+ ESP_LOGW(TAG, \u0022WDT reset info: %s CPU PC\u003d0x%x (waiti mode)\u0022, cpu_name, pc);\n+ } else {\n+ ESP_LOGW(TAG, \u0022WDT reset info: %s CPU PC\u003d0x%x\u0022, cpu_name, pc);\n+ }\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU STATUS 0x%08x\u0022, cpu_name, stat);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PID 0x%08x\u0022, cpu_name, pid);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGINST 0x%08x\u0022, cpu_name, inst);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGSTATUS 0x%08x\u0022, cpu_name, dstat);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGDATA 0x%08x\u0022, cpu_name, data);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGPC 0x%08x\u0022, cpu_name, pc);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGLS0STAT 0x%08x\u0022, cpu_name, lsstat);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08x\u0022, cpu_name, lsaddr);\n+ ESP_LOGD(TAG, \u0022WDT reset info: %s CPU PDEBUGLS0DATA 0x%08x\u0022, cpu_name, lsdata);\n+}\n+\n+static void wdt_reset_check(void)\n+{\n+ int wdt_rst \u003d 0;\n+ RESET_REASON rst_reas[2];\n+\n+ rst_reas[0] \u003d rtc_get_reset_reason(0);\n+ rst_reas[1] \u003d rtc_get_reset_reason(1);\n+ if (rst_reas[0] \u003d\u003d RTCWDT_SYS_RESET || rst_reas[0] \u003d\u003d TG0WDT_SYS_RESET || rst_reas[0] \u003d\u003d TG1WDT_SYS_RESET ||\n+ rst_reas[0] \u003d\u003d TGWDT_CPU_RESET || rst_reas[0] \u003d\u003d RTCWDT_CPU_RESET) {\n+ ESP_LOGW(TAG, \u0022PRO CPU has been reset by WDT.\u0022);\n+ wdt_rst \u003d 1;\n+ }\n+ if (rst_reas[1] \u003d\u003d RTCWDT_SYS_RESET || rst_reas[1] \u003d\u003d TG0WDT_SYS_RESET || rst_reas[1] \u003d\u003d TG1WDT_SYS_RESET ||\n+ rst_reas[1] \u003d\u003d TGWDT_CPU_RESET || rst_reas[1] \u003d\u003d RTCWDT_CPU_RESET) {\n+ ESP_LOGW(TAG, \u0022APP CPU has been reset by WDT.\u0022);\n+ wdt_rst \u003d 1;\n+ }\n+ if (wdt_rst) {\n+ // if reset by WDT dump info from trace port\n+ wdt_reset_info_dump(0);\n+ wdt_reset_info_dump(1);\n+ }\n+ wdt_reset_cpu0_info_enable();\n+}\n+\n+void __assert_func(const char *file, int line, const char *func, const char *expr)\n+{\n+ ESP_LOGE(TAG, \u0022Assert failed in %s, %s:%d (%s)\u0022, func, file, line, expr);\n+ while(1) {}\n+}\ndiff --git a/components/bootloader/subproject/main/component.mk b/components/bootloader/subproject/main/component.mk\nnew file mode 100644\nindex 0000000..df07108\n--- /dev/null\n+++ b/components/bootloader/subproject/main/component.mk\n@@ -0,0 +1,20 @@\n+#\n+# Main bootloader Makefile.\n+#\n+# This is basically the same as a component makefile, but in the case of the bootloader\n+# we pull in bootloader-specific linker arguments.\n+#\n+\n+LINKER_SCRIPTS :\u003d \u005c\n+\tesp32.bootloader.ld \u005c\n+\t$(IDF_PATH)/components/esp32/ld/esp32.rom.ld \u005c\n+\t$(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \u005c\n+\tesp32.bootloader.rom.ld\n+\n+ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH\n+LINKER_SCRIPTS +\u003d $(IDF_PATH)/components/esp32/ld/esp32.rom.spiflash.ld\n+endif\n+\n+COMPONENT_ADD_LDFLAGS +\u003d -L $(COMPONENT_PATH) $(addprefix -T ,$(LINKER_SCRIPTS))\n+\n+COMPONENT_ADD_LINKER_DEPS :\u003d $(LINKER_SCRIPTS)\ndiff --git a/components/bootloader/subproject/main/esp32.bootloader.ld b/components/bootloader/subproject/main/esp32.bootloader.ld\nnew file mode 100644\nindex 0000000..54fe1a9\n--- /dev/null\n+++ b/components/bootloader/subproject/main/esp32.bootloader.ld\n@@ -0,0 +1,132 @@\n+/*\n+Linker file used to link the bootloader.\n+*/\n+\n+\n+/* Simplified memory map for the bootloader\n+\n+ The main purpose is to make sure the bootloader can load into main memory\n+ without overwriting itself.\n+*/\n+MEMORY\n+{\n+ /* I/O */\n+ dport0_seg (RW) : \torg \u003d 0x3FF00000, len \u003d 0x10\n+ /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, the main app enables APP CPU cache */\n+ iram_seg (RWX) : org \u003d 0x40078000, len \u003d 0x8000\n+ /* 64k at the end of DRAM, after ROM bootloader stack */\n+ dram_seg (RW) : \torg \u003d 0x3FFF0000, len \u003d 0x10000\n+}\n+\n+/* Default entry point: */\n+ENTRY(call_start_cpu0);\n+\n+\n+SECTIONS\n+{\n+ .iram1.text :\n+ {\n+ . \u003d ALIGN (16);\n+ *(.entry.text)\n+ *(.init.literal)\n+ *(.init)\n+ } \u003e iram_seg\n+\n+\n+ /* Shared RAM */\n+ .dram0.bss (NOLOAD) :\n+ {\n+ . \u003d ALIGN (8);\n+ _bss_start \u003d ABSOLUTE(.);\n+ *(.dynsbss)\n+ *(.sbss)\n+ *(.sbss.*)\n+ *(.gnu.linkonce.sb.*)\n+ *(.scommon)\n+ *(.sbss2)\n+ *(.sbss2.*)\n+ *(.gnu.linkonce.sb2.*)\n+ *(.dynbss)\n+ *(.bss)\n+ *(.bss.*)\n+ *(.gnu.linkonce.b.*)\n+ *(COMMON)\n+ . \u003d ALIGN (8);\n+ _bss_end \u003d ABSOLUTE(.);\n+ } \u003edram_seg\n+\n+ .dram0.data :\n+ {\n+ _data_start \u003d ABSOLUTE(.);\n+ *(.data)\n+ *(.data.*)\n+ *(.gnu.linkonce.d.*)\n+ *(.data1)\n+ *(.sdata)\n+ *(.sdata.*)\n+ *(.gnu.linkonce.s.*)\n+ *(.sdata2)\n+ *(.sdata2.*)\n+ *(.gnu.linkonce.s2.*)\n+ *(.jcr)\n+ _data_end \u003d ABSOLUTE(.);\n+ } \u003edram_seg\n+\n+ .dram0.rodata :\n+ {\n+ _rodata_start \u003d ABSOLUTE(.);\n+ *(.rodata)\n+ *(.rodata.*)\n+ *(.gnu.linkonce.r.*)\n+ *(.rodata1)\n+ __XT_EXCEPTION_TABLE_ \u003d ABSOLUTE(.);\n+ *(.xt_except_table)\n+ *(.gcc_except_table)\n+ *(.gnu.linkonce.e.*)\n+ *(.gnu.version_r)\n+ *(.eh_frame)\n+ . \u003d (. + 3) \u0026 ~ 3;\n+ /* C++ constructor and destructor tables, properly ordered: */\n+ __init_array_start \u003d ABSOLUTE(.);\n+ KEEP (*crtbegin.o(.ctors))\n+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))\n+ KEEP (*(SORT(.ctors.*)))\n+ KEEP (*(.ctors))\n+ __init_array_end \u003d ABSOLUTE(.);\n+ KEEP (*crtbegin.o(.dtors))\n+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))\n+ KEEP (*(SORT(.dtors.*)))\n+ KEEP (*(.dtors))\n+ /* C++ exception handlers table: */\n+ __XT_EXCEPTION_DESCS_ \u003d ABSOLUTE(.);\n+ *(.xt_except_desc)\n+ *(.gnu.linkonce.h.*)\n+ __XT_EXCEPTION_DESCS_END__ \u003d ABSOLUTE(.);\n+ *(.xt_except_desc_end)\n+ *(.dynamic)\n+ *(.gnu.version_d)\n+ _rodata_end \u003d ABSOLUTE(.);\n+\t/* Literals are also RO data. */\n+ _lit4_start \u003d ABSOLUTE(.);\n+ *(*.lit4)\n+ *(.lit4.*)\n+ *(.gnu.linkonce.lit4.*)\n+ _lit4_end \u003d ABSOLUTE(.);\n+ . \u003d ALIGN(4);\n+ _heap_start \u003d ABSOLUTE(.);\n+ } \u003edram_seg\n+\n+ .iram.text :\n+ {\n+ _stext \u003d .;\n+ _text_start \u003d ABSOLUTE(.);\n+ *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)\n+ *(.iram1 .iram1.*) /* catch stray IRAM_ATTR */\n+ *(.fini.literal)\n+ *(.fini)\n+ *(.gnu.version)\n+ _text_end \u003d ABSOLUTE(.);\n+ _etext \u003d .;\n+ } \u003e iram_seg\n+\n+}\ndiff --git a/components/bootloader/subproject/main/esp32.bootloader.rom.ld b/components/bootloader/subproject/main/esp32.bootloader.rom.ld\nnew file mode 100644\nindex 0000000..70f83bd\n--- /dev/null\n+++ b/components/bootloader/subproject/main/esp32.bootloader.rom.ld\n@@ -0,0 +1 @@\n+PROVIDE ( ets_update_cpu_frequency \u003d 0x40008550 ); /* Updates g_ticks_per_us on the current CPU only; not on the other core */\ndiff --git a/components/bootloader/subproject/main/flash_qio_mode.c b/components/bootloader/subproject/main/flash_qio_mode.c\nnew file mode 100644\nindex 0000000..5233bdf\n--- /dev/null\n+++ b/components/bootloader/subproject/main/flash_qio_mode.c\n@@ -0,0 +1,279 @@\n+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n+//\n+// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+\n+// http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+#include \u003cstddef.h\u003e\n+#include \u003cstdint.h\u003e\n+#include \u0022flash_qio_mode.h\u0022\n+#include \u0022esp_log.h\u0022\n+#include \u0022esp_err.h\u0022\n+#include \u0022rom/spi_flash.h\u0022\n+#include \u0022rom/efuse.h\u0022\n+#include \u0022soc/spi_struct.h\u0022\n+#include \u0022soc/efuse_reg.h\u0022\n+#include \u0022sdkconfig.h\u0022\n+\n+/* SPI flash controller */\n+#define SPIFLASH SPI1\n+\n+/* SPI commands (actual on-wire commands not SPI controller bitmasks)\n+ Suitable for use with the execute_flash_command static function.\n+*/\n+#define CMD_RDID 0x9F\n+#define CMD_WRSR 0x01\n+#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */\n+#define CMD_WREN 0x06\n+#define CMD_WRDI 0x04\n+#define CMD_RDSR 0x05\n+#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */\n+\n+static const char *TAG \u003d \u0022qio_mode\u0022;\n+\n+typedef unsigned (*read_status_fn_t)();\n+typedef void (*write_status_fn_t)(unsigned);\n+\n+typedef struct __attribute__((packed)) {\n+ const char *manufacturer;\n+ uint8_t mfg_id; /* 8-bit JEDEC manufacturer ID */\n+ uint16_t flash_id; /* 16-bit JEDEC flash chip ID */\n+ uint16_t id_mask; /* Bits to match on in flash chip ID */\n+ read_status_fn_t read_status_fn;\n+ write_status_fn_t write_status_fn;\n+ uint8_t status_qio_bit;\n+} qio_info_t;\n+\n+/* Read 8 bit status using RDSR command */\n+static unsigned read_status_8b_rdsr();\n+/* Read 8 bit status (second byte) using RDSR2 command */\n+static unsigned read_status_8b_rdsr2();\n+/* read 16 bit status using RDSR \u0026 RDSR2 (low and high bytes) */\n+static unsigned read_status_16b_rdsr_rdsr2();\n+\n+/* Write 8 bit status using WRSR */\n+static void write_status_8b_wrsr(unsigned new_status);\n+/* Write 8 bit status (second byte) using WRSR2 */\n+static void write_status_8b_wrsr2(unsigned new_status);\n+/* Write 16 bit status using WRSR */\n+static void write_status_16b_wrsr(unsigned new_status);\n+\n+#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */\n+\n+#ifndef CONFIG_BOOTLOADER_SPI_WP_PIN // Set in menuconfig if SPI flasher config is set to a quad mode\n+#define CONFIG_BOOTLOADER_SPI_WP_PIN ESP32_D2WD_WP_GPIO\n+#endif\n+\n+/* Array of known flash chips and data to enable Quad I/O mode\n+\n+ Manufacturer \u0026 flash ID can be tested by running \u0022esptool.py\n+ flash_id\u0022\n+\n+ If manufacturer ID matches, and flash ID ORed with flash ID mask\n+ matches, enable_qio_mode() will execute \u0022Read Cmd\u0022, test if bit\n+ number \u0022QIE Bit\u0022 is set, and if not set it will call \u0022Write Cmd\u0022\n+ with this bit set.\n+\n+ Searching of this table stops when the first match is found.\n+ */\n+const static qio_info_t chip_data[] \u003d {\n+/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */\n+ { \u0022MXIC\u0022, 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },\n+ { \u0022ISSI\u0022, 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */\n+ { \u0022WinBond\u0022, 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },\n+\n+ /* Final entry is default entry, if no other IDs have matched.\n+\n+ This approach works for chips including:\n+ GigaDevice (mfg ID 0xC8, flash IDs including 4016),\n+ FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)\n+ */\n+ { NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },\n+};\n+\n+#define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t))\n+\n+static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,\n+ write_status_fn_t write_status_fn,\n+ uint8_t status_qio_bit);\n+\n+/* Generic function to use the \u0022user command\u0022 SPI controller functionality\n+ to send commands to the SPI flash and read the respopnse.\n+\n+ The command passed here is always the on-the-wire command given to the SPI flash unit.\n+*/\n+static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);\n+\n+/* dummy_len_plus values defined in ROM for SPI flash configuration */\n+extern uint8_t g_rom_spiflash_dummy_len_plus[];\n+\n+void bootloader_enable_qio_mode(void)\n+{\n+ uint32_t old_ctrl_reg;\n+ uint32_t raw_flash_id;\n+ uint8_t mfg_id;\n+ uint16_t flash_id;\n+ int i;\n+\n+ ESP_LOGD(TAG, \u0022Probing for QIO mode enable...\u0022);\n+ esp_rom_spiflash_wait_idle(\u0026g_rom_flashchip);\n+\n+ /* Set up some of the SPIFLASH user/ctrl variables which don't change\n+ while we're probing using execute_flash_command() */\n+ old_ctrl_reg \u003d SPIFLASH.ctrl.val;\n+ SPIFLASH.ctrl.val \u003d SPI_WP_REG; // keep WP high while idle, otherwise leave DIO mode\n+ SPIFLASH.user.usr_dummy \u003d 0;\n+ SPIFLASH.user.usr_addr \u003d 0;\n+ SPIFLASH.user.usr_command \u003d 1;\n+ SPIFLASH.user2.usr_command_bitlen \u003d 7;\n+\n+ raw_flash_id \u003d execute_flash_command(CMD_RDID, 0, 0, 24);\n+ ESP_LOGD(TAG, \u0022Raw SPI flash chip id 0x%x\u0022, raw_flash_id);\n+\n+ mfg_id \u003d raw_flash_id \u0026 0xFF;\n+ flash_id \u003d (raw_flash_id \u003e\u003e 16) | (raw_flash_id \u0026 0xFF00);\n+ ESP_LOGD(TAG, \u0022Manufacturer ID 0x%02x chip ID 0x%04x\u0022, mfg_id, flash_id);\n+\n+ for (i \u003d 0; i \u003c NUM_CHIPS-1; i++) {\n+ const qio_info_t *chip \u003d \u0026chip_data[i];\n+ if (mfg_id \u003d\u003d chip-\u003emfg_id \u0026\u0026 (flash_id \u0026 chip-\u003eid_mask) \u003d\u003d (chip-\u003eflash_id \u0026 chip-\u003eid_mask)) {\n+ ESP_LOGI(TAG, \u0022Enabling QIO for flash chip %s\u0022, chip_data[i].manufacturer);\n+ break;\n+ }\n+ }\n+\n+ if (i \u003d\u003d NUM_CHIPS - 1) {\n+ ESP_LOGI(TAG, \u0022Enabling default flash chip QIO\u0022);\n+ }\n+\n+ esp_err_t res \u003d enable_qio_mode(chip_data[i].read_status_fn,\n+ chip_data[i].write_status_fn,\n+ chip_data[i].status_qio_bit);\n+ if (res !\u003d ESP_OK) {\n+ // Restore SPI flash CTRL setting, to keep us in DIO/DOUT mode\n+ SPIFLASH.ctrl.val \u003d old_ctrl_reg;\n+ }\n+}\n+\n+static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,\n+ write_status_fn_t write_status_fn,\n+ uint8_t status_qio_bit)\n+{\n+ uint32_t status;\n+ const uint32_t spiconfig \u003d ets_efuse_get_spiconfig();\n+\n+ if (spiconfig !\u003d EFUSE_SPICONFIG_SPI_DEFAULTS \u0026\u0026 spiconfig !\u003d EFUSE_SPICONFIG_HSPI_DEFAULTS) {\n+ // spiconfig specifies a custom efuse pin configuration. This config defines all pins -except- WP,\n+ // which is compiled into the bootloader instead.\n+ //\n+ // Most commonly an overriden pin mapping means ESP32-D2WD. Warn if chip is ESP32-D2WD\n+ // but someone has changed the WP pin assignment from that chip's WP pin.\n+ uint32_t chip_ver \u003d REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_RESERVE);\n+ uint32_t pkg_ver \u003d chip_ver \u0026 0x7;\n+ const int PKG_VER_ESP32_D2WD \u003d 2; // TODO: use chip detection API once available\n+ if (pkg_ver \u003d\u003d PKG_VER_ESP32_D2WD \u0026\u0026 CONFIG_BOOTLOADER_SPI_WP_PIN !\u003d ESP32_D2WD_WP_GPIO) {\n+ ESP_LOGW(TAG, \u0022Chip is ESP32-D2WD but flash WP pin is different value to internal flash\u0022);\n+ }\n+ }\n+\n+ esp_rom_spiflash_wait_idle(\u0026g_rom_flashchip);\n+\n+ status \u003d read_status_fn();\n+ ESP_LOGD(TAG, \u0022Initial flash chip status 0x%x\u0022, status);\n+\n+ if ((status \u0026 (1\u003c\u003cstatus_qio_bit)) \u003d\u003d 0) {\n+ execute_flash_command(CMD_WREN, 0, 0, 0);\n+ write_status_fn(status | (1\u003c\u003cstatus_qio_bit));\n+\n+ esp_rom_spiflash_wait_idle(\u0026g_rom_flashchip);\n+\n+ status \u003d read_status_fn();\n+ ESP_LOGD(TAG, \u0022Updated flash chip status 0x%x\u0022, status);\n+ if ((status \u0026 (1\u003c\u003cstatus_qio_bit)) \u003d\u003d 0) {\n+ ESP_LOGE(TAG, \u0022Failed to set QIE bit, not enabling QIO mode\u0022);\n+ return ESP_FAIL;\n+ }\n+\n+ } else {\n+ ESP_LOGD(TAG, \u0022QIO mode already enabled in flash\u0022);\n+ }\n+\n+ ESP_LOGD(TAG, \u0022Enabling QIO mode...\u0022);\n+\n+ esp_rom_spiflash_read_mode_t mode;\n+#if CONFIG_FLASHMODE_QOUT\n+ mode \u003d ESP_ROM_SPIFLASH_QOUT_MODE;\n+#else\n+ mode \u003d ESP_ROM_SPIFLASH_QIO_MODE;\n+#endif\n+\n+ esp_rom_spiflash_config_readmode(mode);\n+\n+ esp_rom_spiflash_select_qio_pins(CONFIG_BOOTLOADER_SPI_WP_PIN, spiconfig);\n+\n+ return ESP_OK;\n+}\n+\n+static unsigned read_status_8b_rdsr()\n+{\n+ return execute_flash_command(CMD_RDSR, 0, 0, 8);\n+}\n+\n+static unsigned read_status_8b_rdsr2()\n+{\n+ return execute_flash_command(CMD_RDSR2, 0, 0, 8);\n+}\n+\n+static unsigned read_status_16b_rdsr_rdsr2()\n+{\n+ return execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) \u003c\u003c 8);\n+}\n+\n+static void write_status_8b_wrsr(unsigned new_status)\n+{\n+ execute_flash_command(CMD_WRSR, new_status, 8, 0);\n+}\n+\n+static void write_status_8b_wrsr2(unsigned new_status)\n+{\n+ execute_flash_command(CMD_WRSR2, new_status, 8, 0);\n+}\n+\n+static void write_status_16b_wrsr(unsigned new_status)\n+{\n+ execute_flash_command(CMD_WRSR, new_status, 16, 0);\n+}\n+\n+static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)\n+{\n+ SPIFLASH.user2.usr_command_value \u003d command;\n+ SPIFLASH.user.usr_miso \u003d miso_len \u003e 0;\n+ SPIFLASH.miso_dlen.usr_miso_dbitlen \u003d miso_len ? (miso_len - 1) : 0;\n+ SPIFLASH.user.usr_mosi \u003d mosi_len \u003e 0;\n+ SPIFLASH.mosi_dlen.usr_mosi_dbitlen \u003d mosi_len ? (mosi_len - 1) : 0;\n+ SPIFLASH.data_buf[0] \u003d mosi_data;\n+\n+ if (g_rom_spiflash_dummy_len_plus[1]) {\n+ /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */\n+ if (miso_len \u003e 0) {\n+ SPIFLASH.user.usr_dummy \u003d 1;\n+ SPIFLASH.user1.usr_dummy_cyclelen \u003d g_rom_spiflash_dummy_len_plus[1] - 1;\n+ } else {\n+ SPIFLASH.user.usr_dummy \u003d 0;\n+ SPIFLASH.user1.usr_dummy_cyclelen \u003d 0;\n+ }\n+ }\n+\n+ SPIFLASH.cmd.usr \u003d 1;\n+ while(SPIFLASH.cmd.usr !\u003d 0)\n+ { }\n+\n+ return SPIFLASH.data_buf[0];\n+}\ndiff --git a/components/bootloader/subproject/main/flash_qio_mode.h b/components/bootloader/subproject/main/flash_qio_mode.h\nnew file mode 100644\nindex 0000000..9efa131\n--- /dev/null\n+++ b/components/bootloader/subproject/main/flash_qio_mode.h\n@@ -0,0 +1,29 @@\n+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n+//\n+// Licensed under the Apache License, Version 2.0 (the \u0022License\u0022);\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+\n+// http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \u0022AS IS\u0022 BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+#pragma once\n+\n+#ifdef __cplusplus\n+extern \u0022C\u0022 {\n+#endif\n+\n+/** @brief Enable Quad I/O mode in bootloader (if configured)\n+ *\n+ * Queries attached SPI flash ID and sends correct SPI flash\n+ * commands to enable QIO or QOUT mode, then enables this mode.\n+ */\n+void bootloader_enable_qio_mode(void);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n","s":{"c":1745562998,"u": 5372}}
],"g": 4673,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}