From 8f3a2b1d0a5a6a76eb14d5ae5e99dc9e3f092f83 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Sun, 11 Dec 2022 18:33:40 -0800 Subject: [PATCH 1/8] Reslove flash address issues with SDK v3.0.0 Fix EEPROM vs RF_CAL flash address conflict. The EEPROM address and RF_CAL address were the same. Add support for Flash size: "Mapping defined by Hardware and Sketch" Change at_partition_table static from dynamic to static. --- cores/esp8266/core_esp8266_main.cpp | 107 +++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 3 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 0b0c4ddc75..dbfe7b1bc2 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -39,6 +39,7 @@ extern "C" { #include #include #include "core_esp8266_vm.h" +#include "flash_hal.h" #define LOOP_TASK_PRIORITY 1 #define LOOP_QUEUE_SIZE 1 @@ -406,6 +407,7 @@ uint32_t __flashindex; #if (NONOSDK >= (0x30000)) +#if 0 extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { uint32_t rf_cal = 0; @@ -457,22 +459,121 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) extern uint32_t user_rf_cal_sector_set(void); user_rf_cal_sector_set(); - const partition_item_t at_partition_table[] = + static partition_item_t at_partition_table[] = { { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, }; +#ifdef DEV_DEBUG_PRINT + extern void set_pll(void); + set_pll(); // fix printing at 115200 bps + ets_uart_printf("\n\nConfig info referenced for system partition table registration:\n"); + ets_uart_printf(" %-17s 0x%08X\n", "PHY_DATA", phy_data); + ets_uart_printf(" %-17s 0x%08X\n", "RF_CAL", rf_cal); + ets_uart_printf(" %-17s 0x%08X\n", "EEPROM Address", EEPROM_start - 0x40200000u); + ets_uart_printf(" %-17s 0x%08X\n", "SYSTEM_PARAMETER", system_parameter); + ets_uart_printf(" %-17s 0x%08X %u\n", "chip_size", flashchip->chip_size, flashchip->chip_size); + ets_uart_printf(" %-17s 0x%08X\n", "EEPROM_start", EEPROM_start); + ets_uart_printf(" %-17s 0x%08X\n", "FS_start", FS_start); + ets_uart_printf(" %-17s 0x%08X\n", "FS_end", FS_end); + ets_uart_printf(" %-17s 0x%08X\n", "FS_page", FS_page); + ets_uart_printf(" %-17s 0x%08X\n", "FS_block", FS_block); + if (!system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) + { + ets_uart_printf("\nSystem partition table registration failed!\n"); + panic(); + } +#else system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); +#endif } +#else +extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) +{ + // For SDKs 3.0.0 and later, place phy_data readonly overlay on top of the + // EEPROM address. For older SDKs without a system partition, RF_CAL and + // PHY_DATA shared the same flash segment. + uint32_t phy_data = EEPROM_start - 0x40200000u; + uint32_t rf_cal = phy_data + 0x1000; + uint32_t system_parameter = rf_cal + 0x1000; + + // Examples show partition table in global address space + static partition_item_t at_partition_table[] = + { + { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, + { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, + { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, + }; + + // For SDKs v3.0.0 and later, the functions `uint32 + // user_rf_cal_sector_set(void)` and `void user_rf_pre_init(void)` are not + // called by the SDK. We need these called to start and stop spoofing logic + // for flash read of PHY Init data. + extern uint32_t user_rf_cal_sector_set(void); + user_rf_cal_sector_set(); // Start spoofing logic + +#ifdef DEV_DEBUG_PRINT + extern void set_pll(void); + set_pll(); // fix printing for 115200 bps + ets_uart_printf("\n\nConfig info referenced for system partition table registration:\n"); + ets_uart_printf(" %-18s 0x%08X\n", "PHY_DATA", phy_data); + ets_uart_printf(" %-18s 0x%08X\n", "RF_CAL", rf_cal); + ets_uart_printf(" %-18s 0x%08X\n", "SYSTEM_PARAMETER", system_parameter); + ets_uart_printf(" %-18s 0x%08X %u\n", "ota_1_sz", user_bin_sz, user_bin_sz); + ets_uart_printf(" %-18s 0x%08X %u\n", "chip_size", flashchip->chip_size, flashchip->chip_size); + ets_uart_printf(" %-18s 0x%08X\n", "EEPROM_start", EEPROM_start); + ets_uart_printf(" %-18s 0x%08X\n", "FS_start", FS_start); + ets_uart_printf(" %-18s 0x%08X\n", "FS_end", FS_end); + ets_uart_printf(" %-18s 0x%08X\n", "FS_page", FS_page); + ets_uart_printf(" %-18s 0x%08X\n", "FS_block", FS_block); + uint32_t configured_chip_size = system_parameter + 4096 * 3; + if (flashchip->chip_size != configured_chip_size) + { + ets_uart_printf("\nMissmatch between actual(%u) vs configured(%u) flash size\n", flashchip->chip_size, configured_chip_size); + panic(); + } + if (!system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) + { + ets_uart_printf("\nSystem partition table registration failed!\n"); + panic(); + } + +#else +//+ restore conditional for final or remove - to be discussed +#if 1 // defined(FLASH_MAP_SUPPORT) && defined(DEBUG_ESP_CORE) + uint32_t configured_chip_size = system_parameter + 4096 * 3; + // flashchip->chip_size is updated by the SDK. The size is based on the + // value patched into the .bin header by esptool. + // system_get_flash_size_map() returns that patched value. + if (flashchip->chip_size != configured_chip_size) + { + // For this message and postmortem to be readable, the console speed may + // need to be 74880 bps. + ets_uart_printf("\nMissmatch between actual(%u) vs configured(%u) flash size\n", flashchip->chip_size, configured_chip_size); + // Full stop to avoid possible stored flash data corruption. This + // missmatch does not occur with flash size selection "Mapping defined by + // Hardware and Sketch". + panic(); + } +#endif + + system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); + // No test for failure !!! + // How to handle failure ??? + // It appears the PLL calibration for CPU clock has not run. + // Postmortem will be unreadable. +#endif +} +#endif #endif extern "C" void user_init(void) { #if (NONOSDK >= (0x30000)) extern void user_rf_pre_init(); - user_rf_pre_init(); + user_rf_pre_init(); // Stop spoofing logic #endif struct rst_info *rtc_info_ptr = system_get_rst_info(); @@ -496,7 +597,7 @@ extern "C" void user_init(void) { install_vm_exception_handler(); #endif -#if defined(NON32XFER_HANDLER) || defined(MMU_IRAM_HEAP) +#if defined(NON32XFER_HANDLER) || (defined(MMU_IRAM_HEAP) && (NONOSDK < (0x30000 - 1))) install_non32xfer_exception_handler(); #endif From 0bcbec760b2aa30ac2bbc1966ec60ce4192f0c71 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Mon, 12 Dec 2022 10:25:09 -0800 Subject: [PATCH 2/8] Cleanup and improve comments --- cores/esp8266/core_esp8266_main.cpp | 166 ++++++++-------------------- 1 file changed, 46 insertions(+), 120 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index dbfe7b1bc2..cad78b6cb2 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -407,105 +407,30 @@ uint32_t __flashindex; #if (NONOSDK >= (0x30000)) -#if 0 -extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) -{ - uint32_t rf_cal = 0; - uint32_t phy_data = 0; - uint32_t system_parameter = 0; - - switch (system_get_flash_size_map()) - { - case FLASH_SIZE_2M: - rf_cal = 0x3b000; - phy_data = 0x3c000; - system_parameter = 0x3d000; - break; - case FLASH_SIZE_4M_MAP_256_256: - rf_cal = 0x7b000; - phy_data = 0x7c000; - system_parameter = 0x7d000; - break; - case FLASH_SIZE_8M_MAP_512_512: - rf_cal = 0xfb000; - phy_data = 0xfc000; - system_parameter = 0xfd000; - break; - case FLASH_SIZE_16M_MAP_512_512: - case FLASH_SIZE_16M_MAP_1024_1024: - rf_cal = 0x1fb000; - phy_data = 0x1fc000; - system_parameter = 0x1fd000; - break; - case FLASH_SIZE_32M_MAP_512_512: - case FLASH_SIZE_32M_MAP_1024_1024: - case FLASH_SIZE_32M_MAP_2048_2048: - rf_cal = 0x3fb000; - phy_data = 0x3fc000; - system_parameter = 0x3fd000; - break; - case FLASH_SIZE_64M_MAP_1024_1024: - rf_cal = 0x7fb000; - phy_data = 0x7fc000; - system_parameter = 0x7fd000; - break; - case FLASH_SIZE_128M_MAP_1024_1024: - rf_cal = 0xffb000; - phy_data = 0xffc000; - system_parameter = 0xffd000; - break; - } - - extern uint32_t user_rf_cal_sector_set(void); - user_rf_cal_sector_set(); - - static partition_item_t at_partition_table[] = - { - { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, - { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, - { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, - }; -#ifdef DEV_DEBUG_PRINT - extern void set_pll(void); - set_pll(); // fix printing at 115200 bps - ets_uart_printf("\n\nConfig info referenced for system partition table registration:\n"); - ets_uart_printf(" %-17s 0x%08X\n", "PHY_DATA", phy_data); - ets_uart_printf(" %-17s 0x%08X\n", "RF_CAL", rf_cal); - ets_uart_printf(" %-17s 0x%08X\n", "EEPROM Address", EEPROM_start - 0x40200000u); - ets_uart_printf(" %-17s 0x%08X\n", "SYSTEM_PARAMETER", system_parameter); - ets_uart_printf(" %-17s 0x%08X %u\n", "chip_size", flashchip->chip_size, flashchip->chip_size); - ets_uart_printf(" %-17s 0x%08X\n", "EEPROM_start", EEPROM_start); - ets_uart_printf(" %-17s 0x%08X\n", "FS_start", FS_start); - ets_uart_printf(" %-17s 0x%08X\n", "FS_end", FS_end); - ets_uart_printf(" %-17s 0x%08X\n", "FS_page", FS_page); - ets_uart_printf(" %-17s 0x%08X\n", "FS_block", FS_block); - if (!system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) - { - ets_uart_printf("\nSystem partition table registration failed!\n"); - panic(); - } -#else - system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); -#endif -} - -#else extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { // For SDKs 3.0.0 and later, place phy_data readonly overlay on top of the // EEPROM address. For older SDKs without a system partition, RF_CAL and // PHY_DATA shared the same flash segment. + // + // For the Arduino ESP8266 core, the sectors for "EEPROM +0x1000", "RF_CAL + // +0x1000", and "SYSTEM_PARAMETERs +0x3000" are positioned in the last five + // sectors of flash memory. PHY_INIT_DATA is special. It is a one time read + // of 128 bytes of data that is provided by a one time spoofed flash read. uint32_t phy_data = EEPROM_start - 0x40200000u; uint32_t rf_cal = phy_data + 0x1000; uint32_t system_parameter = rf_cal + 0x1000; - // Examples show partition table in global address space + // All the examples I find, show the partition table in the global address space. static partition_item_t at_partition_table[] = { { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, }; + // SDK 3.0's `system_partition_table_regist` is FOTA-centric. It will report + // on BOOT, OTA1, and OTA2 being missing. We are Non-FOTA. I don't see + // anything we can do about this. Other than maybe turning off os_print. // For SDKs v3.0.0 and later, the functions `uint32 // user_rf_cal_sector_set(void)` and `void user_rf_pre_init(void)` are not @@ -515,34 +440,20 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) user_rf_cal_sector_set(); // Start spoofing logic #ifdef DEV_DEBUG_PRINT + // Deeper debugging maybe delete this block later extern void set_pll(void); set_pll(); // fix printing for 115200 bps - ets_uart_printf("\n\nConfig info referenced for system partition table registration:\n"); - ets_uart_printf(" %-18s 0x%08X\n", "PHY_DATA", phy_data); - ets_uart_printf(" %-18s 0x%08X\n", "RF_CAL", rf_cal); - ets_uart_printf(" %-18s 0x%08X\n", "SYSTEM_PARAMETER", system_parameter); - ets_uart_printf(" %-18s 0x%08X %u\n", "ota_1_sz", user_bin_sz, user_bin_sz); - ets_uart_printf(" %-18s 0x%08X %u\n", "chip_size", flashchip->chip_size, flashchip->chip_size); - ets_uart_printf(" %-18s 0x%08X\n", "EEPROM_start", EEPROM_start); - ets_uart_printf(" %-18s 0x%08X\n", "FS_start", FS_start); - ets_uart_printf(" %-18s 0x%08X\n", "FS_end", FS_end); - ets_uart_printf(" %-18s 0x%08X\n", "FS_page", FS_page); - ets_uart_printf(" %-18s 0x%08X\n", "FS_block", FS_block); - uint32_t configured_chip_size = system_parameter + 4096 * 3; - if (flashchip->chip_size != configured_chip_size) - { - ets_uart_printf("\nMissmatch between actual(%u) vs configured(%u) flash size\n", flashchip->chip_size, configured_chip_size); - panic(); - } - if (!system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) - { - ets_uart_printf("\nSystem partition table registration failed!\n"); - panic(); - } - -#else -//+ restore conditional for final or remove - to be discussed -#if 1 // defined(FLASH_MAP_SUPPORT) && defined(DEBUG_ESP_CORE) + ets_uart_printf(PSTR("\n\nConfig info referenced for system partition table registration:\n")); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("PHY_DATA"), phy_data); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("RF_CAL"), rf_cal); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("SYSTEM_PARAMETER"), system_parameter); + ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("chip_size"), flashchip->chip_size, flashchip->chip_size); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("EEPROM_start"), EEPROM_start); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_start"), FS_start); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_end"), FS_end); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_page"), FS_page); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_block"), FS_block); +#if !defined(FLASH_MAP_SUPPORT) uint32_t configured_chip_size = system_parameter + 4096 * 3; // flashchip->chip_size is updated by the SDK. The size is based on the // value patched into the .bin header by esptool. @@ -551,23 +462,38 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { // For this message and postmortem to be readable, the console speed may // need to be 74880 bps. - ets_uart_printf("\nMissmatch between actual(%u) vs configured(%u) flash size\n", flashchip->chip_size, configured_chip_size); + ets_uart_printf(PSTR("\nMissmatch between actual(%u) vs configured(%u) flash size\n"), flashchip->chip_size, configured_chip_size); // Full stop to avoid possible stored flash data corruption. This // missmatch does not occur with flash size selection "Mapping defined by // Hardware and Sketch". - panic(); + abort(); } #endif - - system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); - // No test for failure !!! - // How to handle failure ??? - // It appears the PLL calibration for CPU clock has not run. - // Postmortem will be unreadable. #endif + if (!system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) + { + // We will land here anytime the build flash size value set by the Arduino + // IDE Tools menu mismatches the firmware image value detected and updated + // on the fly by esptool. + // + // The SDKs PLL CPU clock calibration hasn't run. For this message and + // postmortem to be readable, the console speed may need to be 74880 bps. + // + // Because SDK v3.0.x always has a non-32-bit wide exception handler + // installed, we can use PROGMEM strings with Boot ROM print functions. + ets_uart_printf(PSTR("\nSystem partition table registration failed!\n")); + + //C What is the best action on failure? + //C * The above printf maybe redundant. `system_partition_table_regist` + //C appears to print specific failure messages. most of the time. + //C * Things will not get better by rebooting. + //C * Most likely the error message was not readable - mismatched console speed + //C * Expressif example do a `while(true){};` on fail. HWDT appears to be + //C off and the device freezes. + abort(); + } } -#endif -#endif +#endif // #if (NONOSDK >= (0x30000)) extern "C" void user_init(void) { From 61e4665b0c15ab2c9329e30f41b1ece20501aa0f Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Mon, 12 Dec 2022 11:56:53 -0800 Subject: [PATCH 3/8] Improve flash size and partition error reporting/indication Changed set_pll() to mmu_set_pll() and made available for debug builds and other settings where required. Provide more checks and feedback in the debug builds and trim code for production. --- cores/esp8266/core_esp8266_main.cpp | 115 ++++++++++++++++------------ cores/esp8266/mmu_iram.cpp | 66 ++++++++-------- cores/esp8266/mmu_iram.h | 16 +++- 3 files changed, 117 insertions(+), 80 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index cad78b6cb2..34bd19a42c 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -407,6 +407,7 @@ uint32_t __flashindex; #if (NONOSDK >= (0x30000)) +extern "C" uint8_t uart_rx_one_char_block(); extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { // For SDKs 3.0.0 and later, place phy_data readonly overlay on top of the @@ -418,8 +419,8 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) // sectors of flash memory. PHY_INIT_DATA is special. It is a one time read // of 128 bytes of data that is provided by a one time spoofed flash read. uint32_t phy_data = EEPROM_start - 0x40200000u; - uint32_t rf_cal = phy_data + 0x1000; - uint32_t system_parameter = rf_cal + 0x1000; + uint32_t rf_cal = phy_data + 0x1000u; + uint32_t system_parameter = rf_cal + 0x1000u; // All the examples I find, show the partition table in the global address space. static partition_item_t at_partition_table[] = @@ -439,58 +440,78 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) extern uint32_t user_rf_cal_sector_set(void); user_rf_cal_sector_set(); // Start spoofing logic -#ifdef DEV_DEBUG_PRINT - // Deeper debugging maybe delete this block later - extern void set_pll(void); - set_pll(); // fix printing for 115200 bps - ets_uart_printf(PSTR("\n\nConfig info referenced for system partition table registration:\n")); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("PHY_DATA"), phy_data); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("RF_CAL"), rf_cal); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("SYSTEM_PARAMETER"), system_parameter); - ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("chip_size"), flashchip->chip_size, flashchip->chip_size); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("EEPROM_start"), EEPROM_start); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_start"), FS_start); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_end"), FS_end); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_page"), FS_page); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_block"), FS_block); -#if !defined(FLASH_MAP_SUPPORT) + // -DALLOW_SMALL_FLASH_SIZE=1 + // Allows for small flash-size builds targeted for multiple devices, + // commonly IoT, of varying flash sizes. + const char *chip_sz_str = NULL; +#if !defined(FLASH_MAP_SUPPORT) & defined(DEBUG_ESP_PORT) & !defined(ALLOW_SMALL_FLASH_SIZE) + // Note, system_partition_table_regist would only catch when the build flash + // size value set by the Arduino IDE Tools menu is larger than firmware + // image value detected and updated on the fly by esptool. uint32_t configured_chip_size = system_parameter + 4096 * 3; // flashchip->chip_size is updated by the SDK. The size is based on the // value patched into the .bin header by esptool. // system_get_flash_size_map() returns that patched value. - if (flashchip->chip_size != configured_chip_size) - { - // For this message and postmortem to be readable, the console speed may - // need to be 74880 bps. - ets_uart_printf(PSTR("\nMissmatch between actual(%u) vs configured(%u) flash size\n"), flashchip->chip_size, configured_chip_size); - // Full stop to avoid possible stored flash data corruption. This - // missmatch does not occur with flash size selection "Mapping defined by - // Hardware and Sketch". - abort(); + if (flashchip->chip_size != configured_chip_size) { + // Full stop to avoid possible stored flash data corruption. This + // mismatch will not occur with flash size selection "Mapping defined by + // Hardware and Sketch". + chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n\n"); } #endif + + if (chip_sz_str || !system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) { + // user_pre_init() is called very early in the SDK startup. When called, + // the PLL CPU clock calibration hasn't not run. Since we are failing, the + // calibration will never complete. And the process will repeat over and + // over. The effective data rate will always be 74880 bps. If we had a + // successful boot, the effective data rate would be 115200 on a restart + // or HWDT. This hack relies on the CPU clock calibration never having + // completed. + + // After flashing, the Arduino Serial Monitor needs a moment to reconnect. + // This also allows time for the FIFO to clear and the host serial port time + // to clear any framing errors. + ets_delay_us(200u * 1000u); // For an uncalibrated CPU Clock, this is close enough. + + #if !defined(F_CRYSTAL) + #define F_CRYSTAL 26000000 + #endif + // For print messages to be readable, the UART clock rate is based on the + // precalibration rate. + if (F_CRYSTAL != 40000000) { + uart_div_modify(0, F_CRYSTAL * 2 / 115200); + ets_delay_us(150); + } + ets_uart_printf("\n\n"); + do { + // Because SDK v3.0.x always has a non-32-bit wide exception handler + // installed, we can use PROGMEM strings with Boot ROM print functions. +#ifdef DEBUG_ESP_CORE + ets_uart_printf(PSTR("Config info referenced for system partition table registration:\n")); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("PHY_DATA"), phy_data); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("RF_CAL"), rf_cal); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("SYSTEM_PARAMETER"), system_parameter); + ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("chip_size"), flashchip->chip_size, flashchip->chip_size); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("EEPROM_start"), EEPROM_start); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_start"), FS_start); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_end"), FS_end); + ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_page"), FS_page); + ets_uart_printf(PSTR(" %-18s 0x%08X\n\n"), PSTR("FS_block"), FS_block); #endif - if (!system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) - { - // We will land here anytime the build flash size value set by the Arduino - // IDE Tools menu mismatches the firmware image value detected and updated - // on the fly by esptool. - // - // The SDKs PLL CPU clock calibration hasn't run. For this message and - // postmortem to be readable, the console speed may need to be 74880 bps. - // - // Because SDK v3.0.x always has a non-32-bit wide exception handler - // installed, we can use PROGMEM strings with Boot ROM print functions. - ets_uart_printf(PSTR("\nSystem partition table registration failed!\n")); - - //C What is the best action on failure? - //C * The above printf maybe redundant. `system_partition_table_regist` - //C appears to print specific failure messages. most of the time. - //C * Things will not get better by rebooting. - //C * Most likely the error message was not readable - mismatched console speed - //C * Expressif example do a `while(true){};` on fail. HWDT appears to be - //C off and the device freezes. - abort(); + if (chip_sz_str) { + ets_uart_printf(chip_sz_str); + } else { +#if defined(DEBUG_ESP_CORE) | defined(DEBUG_ESP_PORT) + // Now that the UART speed is corrected and messages will + // display, run system_partition_table_regist again. + system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); +#endif + ets_uart_printf(PSTR("System partition table registration failed!\n\n")); + } + uart_rx_one_char_block(); // Someone said hello - repeat message + } while(true); + } } #endif // #if (NONOSDK >= (0x30000)) diff --git a/cores/esp8266/mmu_iram.cpp b/cores/esp8266/mmu_iram.cpp index c54e9994c8..0193241890 100644 --- a/cores/esp8266/mmu_iram.cpp +++ b/cores/esp8266/mmu_iram.cpp @@ -122,43 +122,15 @@ void IRAM_ATTR Cache_Read_Disable(void) { } #endif -/* - * Early adjustment for CPU crystal frequency, so debug printing will work. - * This should not be left enabled all the time in Cashe_Read..., I am concerned - * that there may be unknown interference with the NONOS SDK startup. - * - * Inspired by: - * https://github.com/pvvx/esp8266web/blob/2e25559bc489487747205db2ef171d48326b32d4/app/sdklib/system/app_main.c#L581-L591 - */ -extern "C" uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add); -extern "C" void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data); - -extern "C" void IRAM_ATTR set_pll(void) -{ -#if !defined(F_CRYSTAL) -#define F_CRYSTAL 26000000 -#endif - if (F_CRYSTAL != 40000000) { - // At Boot ROM(-BIOS) start, it assumes a 40MHz crystal. - // If it is not, we assume a 26MHz crystal. - // There is no support for 24MHz crustal at this time. - if(rom_i2c_readReg(103,4,1) != 136) { // 8: 40MHz, 136: 26MHz - // Assume 26MHz crystal - // soc_param0: 0: 40MHz, 1: 26MHz, 2: 24MHz - // set 80MHz PLL CPU - rom_i2c_writeReg(103,4,1,136); - rom_i2c_writeReg(103,4,2,145); - } - } -} - //C This was used to probe at different stages of boot the state of the PLL //C register. I think we can get rid of this one. +extern "C" uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add); +extern "C" void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data); extern "C" void IRAM_ATTR dbg_set_pll(void) { char r103_4_1 = rom_i2c_readReg(103,4,1); char r103_4_2 = rom_i2c_readReg(103,4,2); - set_pll(); + mmu_set_pll(); ets_uart_printf("\nrom_i2c_readReg(103,4,1) == %u\n", r103_4_1); ets_uart_printf( "rom_i2c_readReg(103,4,2) == %u\n", r103_4_2); } @@ -196,6 +168,38 @@ extern void Cache_Read_Disable(void); extern void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v); #endif // #if (MMU_ICACHE_SIZE == 0x4000) +/* + * Early adjustment for CPU crystal frequency will allow early debug printing to + * be readable before the SDK initialization is complete. + * This should not be left enabled all the time in Cashe_Read..., I am concerned + * that there may be unknown interference with the NONOS SDK startup. + * It does low-level calls that could clash with the SDKs startup. + * + * Inspired by: + * https://github.com/pvvx/esp8266web/blob/2e25559bc489487747205db2ef171d48326b32d4/app/sdklib/system/app_main.c#L581-L591 + */ +extern "C" uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add); +extern "C" void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data); + +extern "C" void IRAM_ATTR mmu_set_pll(void) +{ +#if !defined(F_CRYSTAL) +#define F_CRYSTAL 26000000 +#endif + if (F_CRYSTAL != 40000000) { + // At Boot ROM(-BIOS) start, it assumes a 40MHz crystal. + // If it is not, we assume a 26MHz crystal. + // There is no support for 24MHz crustal at this time. + if(rom_i2c_readReg(103,4,1) != 136) { // 8: 40MHz, 136: 26MHz + // Assume 26MHz crystal + // soc_param0: 0: 40MHz, 1: 26MHz, 2: 24MHz + // set 80MHz PLL CPU + rom_i2c_writeReg(103,4,1,136); + rom_i2c_writeReg(103,4,2,145); + } + } +} + /* * This wrapper is for running code early from IROM (flash) before the SDK * starts. Since the NONOS SDK will do a full and proper flash device init for diff --git a/cores/esp8266/mmu_iram.h b/cores/esp8266/mmu_iram.h index bb4a33898b..e80c5ec348 100644 --- a/cores/esp8266/mmu_iram.h +++ b/cores/esp8266/mmu_iram.h @@ -46,6 +46,19 @@ extern "C" { */ #endif +#if defined(DEV_DEBUG_PRINT) || defined(DEBUG_ESP_MMU) || defined(DEBUG_ESP_CORE) || defined(DEBUG_ESP_PORT) +/* + * Early adjustment for CPU crystal frequency will allow early debug printing to + * be readable before the SDK initialization is complete. + * + * It is unknown if there are any side effects with SDK startup, but a + * possibility. Out of an abundance of caution, limit the use of mmu_set_pll for + * handling printing in failure cases that finish with a reboot. Or for other + * rare debug contexts. + */ +extern void mmu_set_pll(void); +#endif + /* * DEV_DEBUG_PRINT: * Debug printing macros for printing before before, during, and after @@ -63,11 +76,10 @@ extern "C" { #define DBG_MMU_FLUSH(a) while((USS(a) >> USTXC) & 0xff) {} #if defined(DEV_DEBUG_PRINT) -extern void set_pll(void); extern void dbg_set_pll(void); #define DBG_MMU_PRINTF(fmt, ...) \ -set_pll(); \ +mmu_set_pll(); \ uart_buff_switch(0); \ ets_uart_printf(fmt, ##__VA_ARGS__); \ DBG_MMU_FLUSH(0) From 23a491df8758e0d575c31bd9f1d8cad522665bca Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Tue, 13 Dec 2022 19:36:42 -0800 Subject: [PATCH 4/8] Now supports FLASH_MAP_SUPPORT with SDKs v3.0 RF_CAL and system_parameter always occupy the last 5 sectors of flash memory. --- cores/esp8266/core_esp8266_main.cpp | 97 ++++++++++++++++++++++------- cores/esp8266/flash_hal.h | 10 +-- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 34bd19a42c..71b3bc24a1 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -401,33 +401,60 @@ extern "C" void __disableWiFiAtBootTime (void) #if FLASH_MAP_SUPPORT #include "flash_hal.h" -extern "C" void flashinit (void); +extern "C" bool flashinit (void); +#if (NONOSDK >= (0x30000)) +uint32_t __flashindex __attribute__((section(".noinit"))); +#else uint32_t __flashindex; #endif +#endif #if (NONOSDK >= (0x30000)) extern "C" uint8_t uart_rx_one_char_block(); extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { + const char *flash_map_str = NULL; +#if FLASH_MAP_SUPPORT + __flashindex = 0; + if (!flashinit()) { + flash_map_str = PSTR("flashinit failed\n"); + } +#endif + // For SDKs 3.0.0 and later, place phy_data readonly overlay on top of the // EEPROM address. For older SDKs without a system partition, RF_CAL and // PHY_DATA shared the same flash segment. // - // For the Arduino ESP8266 core, the sectors for "EEPROM +0x1000", "RF_CAL - // +0x1000", and "SYSTEM_PARAMETERs +0x3000" are positioned in the last five - // sectors of flash memory. PHY_INIT_DATA is special. It is a one time read - // of 128 bytes of data that is provided by a one time spoofed flash read. + // For the Arduino ESP8266 core, the sectors for "EEPROM = size - 0x5000", + // "RF_CAL = size - 0x4000", and "SYSTEM_PARAMETER = size - 0x3000" are + // positioned in the last five sectors of flash memory. PHY_INIT_DATA is + // special. It is a one time read of 128 bytes of data that is provided by a + // one time spoofed flash read. +#if FLASH_MAP_SUPPORT + uint32_t flash_size = __flashdesc[__flashindex].flash_size_kb * 1024u; +#else + // flashchip->chip_size is updated by the SDK. The size is based on the + // value patched into the .bin header by esptool. + // system_get_flash_size_map() returns that patched value. + uint32_t flash_size = flashchip->chip_size; +#endif + // Always put RF_CAL and system_parameter in the last 4 sectors of flash chip. + uint32_t rf_cal = flash_size - 0x4000u; + uint32_t system_parameter = flash_size - 0x3000u; + + // system_partition_table_regist will not allow partitions to overlap. + // EEPROM_start is a good choice for phy_data overlay. The SDK does not need + // to know about it. So we can omit it from the table not used until after + // user_init() begins. So it should be safe from conflicts. uint32_t phy_data = EEPROM_start - 0x40200000u; - uint32_t rf_cal = phy_data + 0x1000u; - uint32_t system_parameter = rf_cal + 0x1000u; // All the examples I find, show the partition table in the global address space. static partition_item_t at_partition_table[] = { - { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, - { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, - { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, + { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, // type 5 + { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, // type 4 + { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, // type 6 }; // SDK 3.0's `system_partition_table_regist` is FOTA-centric. It will report // on BOOT, OTA1, and OTA2 being missing. We are Non-FOTA. I don't see @@ -444,14 +471,12 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) // Allows for small flash-size builds targeted for multiple devices, // commonly IoT, of varying flash sizes. const char *chip_sz_str = NULL; + + [[maybe_unused]] uint32_t configured_chip_size = phy_data + 4096 * 5; #if !defined(FLASH_MAP_SUPPORT) & defined(DEBUG_ESP_PORT) & !defined(ALLOW_SMALL_FLASH_SIZE) - // Note, system_partition_table_regist would only catch when the build flash + // Note, system_partition_table_regist will only catch when the build flash // size value set by the Arduino IDE Tools menu is larger than firmware // image value detected and updated on the fly by esptool. - uint32_t configured_chip_size = system_parameter + 4096 * 3; - // flashchip->chip_size is updated by the SDK. The size is based on the - // value patched into the .bin header by esptool. - // system_get_flash_size_map() returns that patched value. if (flashchip->chip_size != configured_chip_size) { // Full stop to avoid possible stored flash data corruption. This // mismatch will not occur with flash size selection "Mapping defined by @@ -460,14 +485,25 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) } #endif - if (chip_sz_str || !system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) { +#if FLASH_MAP_SUPPORT & defined(DEBUG_ESP_PORT) + // This should never fail everything traces back to the results of spi_flash_get_id() + if (flash_size != flashchip->chip_size) { + chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n\n"); + } +#endif + + if (flash_map_str || chip_sz_str || !system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) { // user_pre_init() is called very early in the SDK startup. When called, // the PLL CPU clock calibration hasn't not run. Since we are failing, the // calibration will never complete. And the process will repeat over and // over. The effective data rate will always be 74880 bps. If we had a // successful boot, the effective data rate would be 115200 on a restart // or HWDT. This hack relies on the CPU clock calibration never having - // completed. + // completed. This assumes we are starting from a hard reset. + + // A possible exception would be a soft reset after flashing. In which + // case the message will not be readable until after a hard reset or + // power cycle. // After flashing, the Arduino Serial Monitor needs a moment to reconnect. // This also allows time for the FIFO to clear and the host serial port time @@ -493,25 +529,40 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("RF_CAL"), rf_cal); ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("SYSTEM_PARAMETER"), system_parameter); ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("chip_size"), flashchip->chip_size, flashchip->chip_size); +#if FLASH_MAP_SUPPORT + ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("flash_size"), flash_size, flash_size); +#else + ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("config_flash_size"), configured_chip_size, configured_chip_size); +#endif ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("EEPROM_start"), EEPROM_start); ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_start"), FS_start); ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_end"), FS_end); ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_page"), FS_page); ets_uart_printf(PSTR(" %-18s 0x%08X\n\n"), PSTR("FS_block"), FS_block); #endif + +#if FLASH_MAP_SUPPORT + if (flash_map_str) { + ets_uart_printf(flash_map_str); + } else +#endif +#if !defined(FLASH_MAP_SUPPORT) & defined(DEBUG_ESP_PORT) & !defined(ALLOW_SMALL_FLASH_SIZE) if (chip_sz_str) { ets_uart_printf(chip_sz_str); - } else { + } else +#endif + { #if defined(DEBUG_ESP_CORE) | defined(DEBUG_ESP_PORT) // Now that the UART speed is corrected and messages will - // display, run system_partition_table_regist again. + // display, run system_partition_table_regist again to repeat + // the error messages. system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); #endif ets_uart_printf(PSTR("System partition table registration failed!\n\n")); } + uart_rx_one_char_block(); // Someone said hello - repeat message } while(true); - } } #endif // #if (NONOSDK >= (0x30000)) @@ -551,8 +602,10 @@ extern "C" void user_init(void) { #if defined(MMU_IRAM_HEAP) umm_init_iram(); #endif -#if FLASH_MAP_SUPPORT - flashinit(); +#if FLASH_MAP_SUPPORT & (NONOSDK < 0x30000) + if (!flashinit()) { + panic(); + } #endif preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable. __disableWiFiAtBootTime(); // default weak function disables WiFi diff --git a/cores/esp8266/flash_hal.h b/cores/esp8266/flash_hal.h index effca0f965..51500d8b11 100644 --- a/cores/esp8266/flash_hal.h +++ b/cores/esp8266/flash_hal.h @@ -33,21 +33,21 @@ extern "C" { #include extern uint32_t spi_flash_get_id (void); // -extern void flashinit(void); +extern bool flashinit(void); extern uint32_t __flashindex; extern const flash_map_s __flashdesc[]; #define FLASH_MAP_SETUP_CONFIG(conf) FLASH_MAP_SETUP_CONFIG_ATTR(,conf) #define FLASH_MAP_SETUP_CONFIG_ATTR(attr, conf...) \ const flash_map_s __flashdesc[] PROGMEM = conf; \ - void flashinit (void) attr; \ - void flashinit (void) \ + bool flashinit (void) attr; \ + bool flashinit (void) \ { \ uint32_t flash_chip_size_kb = 1 << (((spi_flash_get_id() >> 16) & 0xff) - 10); \ for (__flashindex = 0; __flashindex < sizeof(__flashdesc) / sizeof(__flashdesc[0]); __flashindex++) \ if (__flashdesc[__flashindex].flash_size_kb == flash_chip_size_kb) \ - return; \ - panic(); /* configuration not found */ \ + return true; \ + return false; /* configuration not found */ \ } #define EEPROM_start (__flashdesc[__flashindex].eeprom_start) From b4b7be06590de5bd40243ea34a37bce9a2bcaa70 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Wed, 14 Dec 2022 17:32:08 -0800 Subject: [PATCH 5/8] cleanup and refactoring comment cleanup --- cores/esp8266/core_esp8266_main.cpp | 266 ++++++++++++++++------------ cores/esp8266/core_esp8266_phy.cpp | 18 ++ 2 files changed, 173 insertions(+), 111 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 71b3bc24a1..7510b6888e 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -410,89 +410,112 @@ uint32_t __flashindex; #endif #if (NONOSDK >= (0x30000)) - +#undef ETS_PRINTF +#define ETS_PRINTF(...) ets_uart_printf(__VA_ARGS__) extern "C" uint8_t uart_rx_one_char_block(); + extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { const char *flash_map_str = NULL; -#if FLASH_MAP_SUPPORT - __flashindex = 0; - if (!flashinit()) { - flash_map_str = PSTR("flashinit failed\n"); - } -#endif - - // For SDKs 3.0.0 and later, place phy_data readonly overlay on top of the - // EEPROM address. For older SDKs without a system partition, RF_CAL and - // PHY_DATA shared the same flash segment. - // - // For the Arduino ESP8266 core, the sectors for "EEPROM = size - 0x5000", - // "RF_CAL = size - 0x4000", and "SYSTEM_PARAMETER = size - 0x3000" are - // positioned in the last five sectors of flash memory. PHY_INIT_DATA is - // special. It is a one time read of 128 bytes of data that is provided by a - // one time spoofed flash read. -#if FLASH_MAP_SUPPORT - uint32_t flash_size = __flashdesc[__flashindex].flash_size_kb * 1024u; -#else - // flashchip->chip_size is updated by the SDK. The size is based on the - // value patched into the .bin header by esptool. - // system_get_flash_size_map() returns that patched value. - uint32_t flash_size = flashchip->chip_size; -#endif - // Always put RF_CAL and system_parameter in the last 4 sectors of flash chip. - uint32_t rf_cal = flash_size - 0x4000u; - uint32_t system_parameter = flash_size - 0x3000u; - - // system_partition_table_regist will not allow partitions to overlap. - // EEPROM_start is a good choice for phy_data overlay. The SDK does not need - // to know about it. So we can omit it from the table not used until after - // user_init() begins. So it should be safe from conflicts. - uint32_t phy_data = EEPROM_start - 0x40200000u; - - // All the examples I find, show the partition table in the global address space. - static partition_item_t at_partition_table[] = - { - { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, // type 5 - { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, // type 4 - { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, // type 6 - }; - // SDK 3.0's `system_partition_table_regist` is FOTA-centric. It will report - // on BOOT, OTA1, and OTA2 being missing. We are Non-FOTA. I don't see - // anything we can do about this. Other than maybe turning off os_print. - - // For SDKs v3.0.0 and later, the functions `uint32 - // user_rf_cal_sector_set(void)` and `void user_rf_pre_init(void)` are not - // called by the SDK. We need these called to start and stop spoofing logic - // for flash read of PHY Init data. - extern uint32_t user_rf_cal_sector_set(void); - user_rf_cal_sector_set(); // Start spoofing logic - - // -DALLOW_SMALL_FLASH_SIZE=1 - // Allows for small flash-size builds targeted for multiple devices, - // commonly IoT, of varying flash sizes. const char *chip_sz_str = NULL; + const char *table_regist_str = NULL; + [[maybe_unused]] uint32_t ld_config_chip_size = 0; + uint32_t flash_size = 0; + uint32_t phy_data = 0; + uint32_t rf_cal = 0; + uint32_t system_parameter = 0; + [[maybe_unused]] partition_item_t *_at_partition_table = NULL; + size_t _at_partition_table_sz = 0; + + do { + #if FLASH_MAP_SUPPORT + if (!flashinit()) { + flash_map_str = PSTR("flashinit: flash size missing from FLASH_MAP table\n"); + continue; + } + #endif - [[maybe_unused]] uint32_t configured_chip_size = phy_data + 4096 * 5; -#if !defined(FLASH_MAP_SUPPORT) & defined(DEBUG_ESP_PORT) & !defined(ALLOW_SMALL_FLASH_SIZE) - // Note, system_partition_table_regist will only catch when the build flash - // size value set by the Arduino IDE Tools menu is larger than firmware - // image value detected and updated on the fly by esptool. - if (flashchip->chip_size != configured_chip_size) { - // Full stop to avoid possible stored flash data corruption. This - // mismatch will not occur with flash size selection "Mapping defined by - // Hardware and Sketch". - chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n\n"); - } -#endif + // For SDKs 3.0.0 and later, place phy_data readonly overlay on top of + // the EEPROM address. For older SDKs without a system partition, RF_CAL + // and PHY_DATA shared the same flash segment. + // + // For the Arduino ESP8266 core, the sectors for "EEPROM = size - + // 0x5000", "RF_CAL = size - 0x4000", and "SYSTEM_PARAMETER = size - + // 0x3000" are positioned in the last five sectors of flash memory. + // PHY_INIT_DATA is special. It is a one time read of 128 bytes of data + // that is provided by a spoofed flash read. + #if FLASH_MAP_SUPPORT + flash_size = __flashdesc[__flashindex].flash_size_kb * 1024u; + #else + // flashchip->chip_size is updated by the SDK. The size is based on the + // value patched into the .bin header by esptool. + // system_get_flash_size_map() returns that patched value. + flash_size = flashchip->chip_size; + #endif -#if FLASH_MAP_SUPPORT & defined(DEBUG_ESP_PORT) - // This should never fail everything traces back to the results of spi_flash_get_id() - if (flash_size != flashchip->chip_size) { - chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n\n"); - } -#endif + // For all configurations, place RF_CAL and system_parameter in the + // last 4 sectors of the flash chip. + rf_cal = flash_size - 0x4000u; + system_parameter = flash_size - 0x3000u; + + // The system_partition_table_regist will not allow partitions to + // overlap. EEPROM_start is a good choice for phy_data overlay. The SDK + // does not need to know about EEPROM_start. So we can omit it from the + // table. The real EEPROM access is after user_init() begins long after + // the PHY_DATA read. So it should be safe from conflicts. + phy_data = EEPROM_start - 0x40200000u; + + // For SDKs 3.0 builds, "sdk3_begin_phy_data_spoof and + // user_rf_cal_sector_set" starts and stops the spoofing logic in + // `core_esp8266_phy.cpp`. + extern void sdk3_begin_phy_data_spoof(); + sdk3_begin_phy_data_spoof(); + + ld_config_chip_size = phy_data + 4096 * 5; + + // -DALLOW_SMALL_FLASH_SIZE=1 + // Allows for small flash-size builds targeted for multiple devices, + // commonly IoT, of varying flash sizes. + #if !defined(FLASH_MAP_SUPPORT) & !defined(ALLOW_SMALL_FLASH_SIZE) + // Note, system_partition_table_regist will only catch when the build + // flash size value set by the Arduino IDE Tools menu is larger than + // the firmware image value detected and updated on the fly by esptool. + if (flashchip->chip_size != ld_config_chip_size) { + // Stop to avoid possible stored flash data corruption. This + // mismatch will not occur with flash size selection "Mapping + // defined by Hardware and Sketch". + chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n"); + continue; + } + #endif - if (flash_map_str || chip_sz_str || !system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map())) { + #if FLASH_MAP_SUPPORT & defined(DEBUG_ESP_PORT) + // I don't think this will ever fail. Everything traces back to the results of spi_flash_get_id() + if (flash_size != flashchip->chip_size) { + chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n"); + continue; + } + #endif + + // All the examples I find, show the partition table in the global address space. + static partition_item_t at_partition_table[] = + { + { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, // type 5 + { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, // type 4 + { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, // type 6 + }; + _at_partition_table = at_partition_table; + _at_partition_table_sz = sizeof(at_partition_table) / sizeof(at_partition_table[0]); + // SDK 3.0's `system_partition_table_regist` is FOTA-centric. It will report + // on BOOT, OTA1, and OTA2 being missing. We are Non-FOTA. I don't see + // anything we can do about this. Other than maybe turning off os_print. + if (!system_partition_table_regist(at_partition_table, _at_partition_table_sz, system_get_flash_size_map())) { + table_regist_str = PSTR("System partition table registration failed!\n"); + continue; + } + } while(false); + + if (chip_sz_str || flash_map_str || table_regist_str) { // user_pre_init() is called very early in the SDK startup. When called, // the PLL CPU clock calibration hasn't not run. Since we are failing, the // calibration will never complete. And the process will repeat over and @@ -505,9 +528,9 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) // case the message will not be readable until after a hard reset or // power cycle. - // After flashing, the Arduino Serial Monitor needs a moment to reconnect. - // This also allows time for the FIFO to clear and the host serial port time - // to clear any framing errors. + // After flashing, the Arduino Serial Monitor needs a moment to + // reconnect. This also allows time for the FIFO to clear and the host + // serial port to clear any framing errors. ets_delay_us(200u * 1000u); // For an uncalibrated CPU Clock, this is close enough. #if !defined(F_CRYSTAL) @@ -519,48 +542,69 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) uart_div_modify(0, F_CRYSTAL * 2 / 115200); ets_delay_us(150); } - ets_uart_printf("\n\n"); do { + ETS_PRINTF("\n\n"); // Because SDK v3.0.x always has a non-32-bit wide exception handler // installed, we can use PROGMEM strings with Boot ROM print functions. -#ifdef DEBUG_ESP_CORE - ets_uart_printf(PSTR("Config info referenced for system partition table registration:\n")); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("PHY_DATA"), phy_data); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("RF_CAL"), rf_cal); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("SYSTEM_PARAMETER"), system_parameter); - ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("chip_size"), flashchip->chip_size, flashchip->chip_size); -#if FLASH_MAP_SUPPORT - ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("flash_size"), flash_size, flash_size); +#if defined(DEBUG_ESP_CORE) | defined(DEBUG_ESP_PORT) // DEBUG_ESP_CORE => verbose + #if FLASH_MAP_SUPPORT + if (flash_map_str) { + ETS_PRINTF(flash_map_str); + #if defined(DEBUG_ESP_CORE) + size_t num = __flashindex; // On failure __flashindex is the size of __flashdesc[]; :/ + ETS_PRINTF(PSTR("Table of __flashdesc[%u].flash_size_kb entries converted to bytes:\n"), num); + for (size_t i = 0; i < num; i++) { + uint32_t size = __flashdesc[i].flash_size_kb << 10; + ETS_PRINTF(PSTR(" [%02u] 0x%08X %8u\n"), i, size, size); + } + ETS_PRINTF(PSTR("Reference info:\n")); + uint32_t flash_chip_size = 1 << ((spi_flash_get_id() >> 16) & 0xff); + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("fn(spi_flash_get_id())"), flash_chip_size, flash_chip_size); + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("bin_chip_size"), flashchip->chip_size, flashchip->chip_size); + #endif + } else + #endif + if (chip_sz_str) { + ETS_PRINTF(chip_sz_str); + } else + if (table_regist_str) { + ETS_PRINTF(table_regist_str); + // (printing now works) repeat ...regist error messages + system_partition_table_regist(_at_partition_table, _at_partition_table_sz, system_get_flash_size_map()); + } + if (chip_sz_str || table_regist_str) { + ETS_PRINTF(PSTR("Reference info:\n")); + #if FLASH_MAP_SUPPORT + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("fn(...ex].flash_size_kb)"), flash_size, flash_size); + uint32_t flash_chip_size = 1 << ((spi_flash_get_id() >> 16) & 0xff); + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("fn(spi_flash_get_id())"), flash_chip_size, flash_chip_size); + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("bin_chip_size"), flashchip->chip_size, flashchip->chip_size); + #else + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("config_flash_size"), ld_config_chip_size, ld_config_chip_size); + ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("bin_chip_size"), flashchip->chip_size, flashchip->chip_size); + #endif + #if defined(DEBUG_ESP_CORE) + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("PHY_DATA"), phy_data); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("RF_CAL"), rf_cal); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("SYSTEM_PARAMETER"), system_parameter); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("EEPROM_start"), EEPROM_start); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("FS_start"), FS_start); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("FS_end"), FS_end); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("FS_page"), FS_page); + ETS_PRINTF(PSTR(" %-24s 0x%08X\n"), PSTR("FS_block"), FS_block); + #endif + } #else - ets_uart_printf(PSTR(" %-18s 0x%08X %u\n"), PSTR("config_flash_size"), configured_chip_size, configured_chip_size); -#endif - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("EEPROM_start"), EEPROM_start); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_start"), FS_start); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_end"), FS_end); - ets_uart_printf(PSTR(" %-18s 0x%08X\n"), PSTR("FS_page"), FS_page); - ets_uart_printf(PSTR(" %-18s 0x%08X\n\n"), PSTR("FS_block"), FS_block); -#endif - -#if FLASH_MAP_SUPPORT if (flash_map_str) { - ets_uart_printf(flash_map_str); + ETS_PRINTF(flash_map_str); } else -#endif -#if !defined(FLASH_MAP_SUPPORT) & defined(DEBUG_ESP_PORT) & !defined(ALLOW_SMALL_FLASH_SIZE) if (chip_sz_str) { - ets_uart_printf(chip_sz_str); + ETS_PRINTF(chip_sz_str); } else -#endif - { -#if defined(DEBUG_ESP_CORE) | defined(DEBUG_ESP_PORT) - // Now that the UART speed is corrected and messages will - // display, run system_partition_table_regist again to repeat - // the error messages. - system_partition_table_regist(at_partition_table, sizeof(at_partition_table) / sizeof(at_partition_table[0]), system_get_flash_size_map()); -#endif - ets_uart_printf(PSTR("System partition table registration failed!\n\n")); + if (table_regist_str) { + ETS_PRINTF(table_regist_str); } - +#endif uart_rx_one_char_block(); // Someone said hello - repeat message } while(true); } diff --git a/cores/esp8266/core_esp8266_phy.cpp b/cores/esp8266/core_esp8266_phy.cpp index f06a698bf7..4a32b44810 100644 --- a/cores/esp8266/core_esp8266_phy.cpp +++ b/cores/esp8266/core_esp8266_phy.cpp @@ -303,6 +303,17 @@ extern int __real_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size); extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size); extern int __get_adc_mode(); +/* + Verified that the wide filtering of all 128 byte flash reads during + spoof_init_data continues to be safe for SDK 3.0.5 + From start call to user_pre_init() to stop call with user_rf_pre_init(). + + flash read count during spoof_init_data 4 + flash read 0x00000 8 // system_get_flash_size_map() + flash read 0x00000 4 // system_partition_table_regist() + flash read 0xFB000 128 // PHY_DATA (EEPROM address space) + flash read 0xFC000 628 // RC_CAL + */ extern int IRAM_ATTR __wrap_spi_flash_read(uint32_t addr, uint32_t* dst, size_t size) { if (!spoof_init_data || size != 128) { @@ -332,11 +343,18 @@ extern void __run_user_rf_pre_init(void) return; // default do noting } +#if (NONOSDK >= (0x30000)) +void sdk3_begin_phy_data_spoof(void) +{ + spoof_init_data = true; +} +#else uint32_t user_rf_cal_sector_set(void) { spoof_init_data = true; return flashchip->chip_size/SPI_FLASH_SEC_SIZE - 4; } +#endif void user_rf_pre_init() { From d42bbdb25137a32a48309421f454e60a4bc9d37b Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Thu, 15 Dec 2022 09:28:33 -0800 Subject: [PATCH 6/8] Add more build issolation when including flash_hal.h --- cores/esp8266/core_esp8266_main.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 7510b6888e..d87c220ec7 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -39,7 +39,6 @@ extern "C" { #include #include #include "core_esp8266_vm.h" -#include "flash_hal.h" #define LOOP_TASK_PRIORITY 1 #define LOOP_QUEUE_SIZE 1 @@ -414,6 +413,10 @@ uint32_t __flashindex; #define ETS_PRINTF(...) ets_uart_printf(__VA_ARGS__) extern "C" uint8_t uart_rx_one_char_block(); +#if ! FLASH_MAP_SUPPORT +#include "flash_hal.h" +#endif + extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) { const char *flash_map_str = NULL; @@ -487,6 +490,11 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n"); continue; } + #elif defined(ALLOW_SMALL_FLASH_SIZE) && !defined(FLASH_MAP_SUPPORT) + // Note, while EEPROM is confined to a smaller flash size, we are still + // placing RF_CAL and SYSTEM_PARAMETER at the end of flash. To prevent + // this, esptool or its equal needs to not update the flash size in the + // .bin image. #endif #if FLASH_MAP_SUPPORT & defined(DEBUG_ESP_PORT) From 0cd76504b16dcdde4c61227b645346abe8b90254 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Thu, 15 Dec 2022 11:38:16 -0800 Subject: [PATCH 7/8] Improve details for autoconfig fail. --- cores/esp8266/core_esp8266_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index d87c220ec7..417de99984 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -565,11 +565,11 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) uint32_t size = __flashdesc[i].flash_size_kb << 10; ETS_PRINTF(PSTR(" [%02u] 0x%08X %8u\n"), i, size, size); } + #endif ETS_PRINTF(PSTR("Reference info:\n")); uint32_t flash_chip_size = 1 << ((spi_flash_get_id() >> 16) & 0xff); ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("fn(spi_flash_get_id())"), flash_chip_size, flash_chip_size); ETS_PRINTF(PSTR(" %-24s 0x%08X %8u\n"), PSTR("bin_chip_size"), flashchip->chip_size, flashchip->chip_size); - #endif } else #endif if (chip_sz_str) { From c3e22f070be1fbf5a695673c56d0d464519afe2f Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Sat, 17 Dec 2022 08:42:18 -0800 Subject: [PATCH 8/8] requested changes --- cores/esp8266/core_esp8266_main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 417de99984..a143b1cd5e 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -427,7 +427,7 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) uint32_t phy_data = 0; uint32_t rf_cal = 0; uint32_t system_parameter = 0; - [[maybe_unused]] partition_item_t *_at_partition_table = NULL; + [[maybe_unused]] const partition_item_t *_at_partition_table = NULL; size_t _at_partition_table_sz = 0; do { @@ -479,7 +479,7 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) // -DALLOW_SMALL_FLASH_SIZE=1 // Allows for small flash-size builds targeted for multiple devices, // commonly IoT, of varying flash sizes. - #if !defined(FLASH_MAP_SUPPORT) & !defined(ALLOW_SMALL_FLASH_SIZE) + #if !defined(FLASH_MAP_SUPPORT) && !defined(ALLOW_SMALL_FLASH_SIZE) // Note, system_partition_table_regist will only catch when the build // flash size value set by the Arduino IDE Tools menu is larger than // the firmware image value detected and updated on the fly by esptool. @@ -497,7 +497,7 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) // .bin image. #endif - #if FLASH_MAP_SUPPORT & defined(DEBUG_ESP_PORT) + #if FLASH_MAP_SUPPORT && defined(DEBUG_ESP_PORT) // I don't think this will ever fail. Everything traces back to the results of spi_flash_get_id() if (flash_size != flashchip->chip_size) { chip_sz_str = PSTR("Flash size mismatch, check that the build setting matches the device.\n"); @@ -506,14 +506,14 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) #endif // All the examples I find, show the partition table in the global address space. - static partition_item_t at_partition_table[] = + static const partition_item_t at_partition_table[] = { { SYSTEM_PARTITION_PHY_DATA, phy_data, 0x1000 }, // type 5 { SYSTEM_PARTITION_RF_CAL, rf_cal, 0x1000 }, // type 4 { SYSTEM_PARTITION_SYSTEM_PARAMETER, system_parameter, 0x3000 }, // type 6 }; _at_partition_table = at_partition_table; - _at_partition_table_sz = sizeof(at_partition_table) / sizeof(at_partition_table[0]); + _at_partition_table_sz = std::size(at_partition_table); // SDK 3.0's `system_partition_table_regist` is FOTA-centric. It will report // on BOOT, OTA1, and OTA2 being missing. We are Non-FOTA. I don't see // anything we can do about this. Other than maybe turning off os_print. @@ -554,7 +554,7 @@ extern "C" void ICACHE_FLASH_ATTR user_pre_init(void) ETS_PRINTF("\n\n"); // Because SDK v3.0.x always has a non-32-bit wide exception handler // installed, we can use PROGMEM strings with Boot ROM print functions. -#if defined(DEBUG_ESP_CORE) | defined(DEBUG_ESP_PORT) // DEBUG_ESP_CORE => verbose +#if defined(DEBUG_ESP_CORE) || defined(DEBUG_ESP_PORT) // DEBUG_ESP_CORE => verbose #if FLASH_MAP_SUPPORT if (flash_map_str) { ETS_PRINTF(flash_map_str); @@ -654,7 +654,7 @@ extern "C" void user_init(void) { #if defined(MMU_IRAM_HEAP) umm_init_iram(); #endif -#if FLASH_MAP_SUPPORT & (NONOSDK < 0x30000) +#if FLASH_MAP_SUPPORT && (NONOSDK < 0x30000) if (!flashinit()) { panic(); }