/* * SPDX-FileCopyrightText: 2016 Cesanta Software Limited * * SPDX-License-Identifier: GPL-2.0-or-later * * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD */ /* * Main flasher stub logic * * This stub uses the same SLIP framing and basic command/response structure * as the in-ROM flasher program, but with some enhanced * functions and also standardizes the flasher features between different chips. * * Actual command handlers are implemented in stub_commands.c */ #include #include "stub_flasher.h" #include "rom_functions.h" #include "slip.h" #include "stub_commands.h" #include "stub_write_flash.h" #include "stub_io.h" #include "soc_support.h" /* Buffers for reading from UART. Data is read double-buffered, so we can read into one buffer while handling data from the other one (used for flashing throughput.) */ typedef struct { uint8_t buf_a[MAX_WRITE_BLOCK+64]; uint8_t buf_b[MAX_WRITE_BLOCK+64]; volatile uint8_t *reading_buf; /* Pointer to buf_a, or buf_b - which are we reading_buf? */ uint16_t read; /* how many bytes have we read in the frame */ slip_state_t state; esp_command_req_t *command; /* Pointer to buf_a or buf_b as latest command received */ } uart_buf_t; static volatile uart_buf_t ub; /* esptool protocol "checksum" is XOR of 0xef and each byte of data payload. */ static uint8_t calculate_checksum(uint8_t *buf, int length) { uint8_t res = 0xef; for(int i = 0; i < length; i++) { res ^= buf[i]; } return res; } #if USE_MAX_CPU_FREQ static bool can_use_max_cpu_freq() { /* Check if any of available USB modes are being used. */ #if WITH_USB_OTG && !WITH_USB_JTAG_SERIAL return stub_uses_usb_otg(); #elif !WITH_USB_OTG && WITH_USB_JTAG_SERIAL return stub_uses_usb_jtag_serial(); #elif WITH_USB_OTG && WITH_USB_JTAG_SERIAL return stub_uses_usb_otg() || stub_uses_usb_jtag_serial(); #else return false; #endif } #if ESP32C6 || ESP32H2 || ESP32C5BETA3 static uint32_t pcr_sysclk_conf_reg = 0; #else static uint32_t cpu_per_conf_reg = 0; static uint32_t sysclk_conf_reg = 0; #endif static void set_max_cpu_freq() { if (can_use_max_cpu_freq()) { /* Set CPU frequency to max. This also increases SPI speed. */ #if ESP32C6 || ESP32H2 || ESP32C5BETA3 pcr_sysclk_conf_reg = READ_REG(PCR_SYSCLK_CONF_REG); WRITE_REG(PCR_SYSCLK_CONF_REG, (pcr_sysclk_conf_reg & ~PCR_SOC_CLK_SEL_M) | (PCR_SOC_CLK_MAX << PCR_SOC_CLK_SEL_S)); #else cpu_per_conf_reg = READ_REG(SYSTEM_CPU_PER_CONF_REG); sysclk_conf_reg = READ_REG(SYSTEM_SYSCLK_CONF_REG); WRITE_REG(SYSTEM_SYSCLK_CONF_REG, (sysclk_conf_reg & ~SYSTEM_SOC_CLK_SEL_M) | (SYSTEM_SOC_CLK_MAX << SYSTEM_SOC_CLK_SEL_S)); ets_delay_us(100); /* Leave some time for the change to settle, needed for ESP32-S3 */ WRITE_REG(SYSTEM_CPU_PER_CONF_REG, (cpu_per_conf_reg & ~SYSTEM_CPUPERIOD_SEL_M) | (SYSTEM_CPUPERIOD_MAX << SYSTEM_CPUPERIOD_SEL_S)); #endif } } static void reset_cpu_freq() { /* Restore saved sysclk_conf and cpu_per_conf registers. Use only if set_max_cpu_freq() has been called. */ #if ESP32C6 || ESP32H2 || ESP32C5BETA3 if (can_use_max_cpu_freq() && pcr_sysclk_conf_reg != 0) { WRITE_REG(PCR_SYSCLK_CONF_REG, (READ_REG(PCR_SYSCLK_CONF_REG) & ~PCR_SOC_CLK_SEL_M) | (pcr_sysclk_conf_reg & PCR_SOC_CLK_SEL_M)); } #else if (can_use_max_cpu_freq() && sysclk_conf_reg != 0 && cpu_per_conf_reg != 0) { WRITE_REG(SYSTEM_CPU_PER_CONF_REG, (READ_REG(SYSTEM_CPU_PER_CONF_REG) & ~SYSTEM_CPUPERIOD_SEL_M) | (cpu_per_conf_reg & SYSTEM_CPUPERIOD_SEL_M)); WRITE_REG(SYSTEM_SYSCLK_CONF_REG, (READ_REG(SYSTEM_SYSCLK_CONF_REG) & ~SYSTEM_SOC_CLK_SEL_M) | (sysclk_conf_reg & SYSTEM_SOC_CLK_SEL_M)); } #endif } #endif // USE_MAX_CPU_FREQ #if WITH_USB_JTAG_SERIAL static void disable_watchdogs() { if (stub_uses_usb_jtag_serial()) { WRITE_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY); // Disable write protection WRITE_REG(RTC_CNTL_WDTCONFIG0_REG, 0x0); // Disable RTC watchdog WRITE_REG(RTC_CNTL_WDTWPROTECT_REG, 0x0); // Re-enable write protection WRITE_REG(RTC_CNTL_SWD_WPROTECT_REG, RTC_CNTL_SWD_WKEY); // Disable write protection REG_SET_MASK(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN); // Autofeed super watchdog WRITE_REG(RTC_CNTL_SWD_WPROTECT_REG, 0x0); // Re-enable write protection } } #endif // WITH_USB_JTAG_SERIAL #if ESP32S3 && !ESP32S3BETA2 bool large_flash_mode = false; bool flash_larger_than_16mb() { uint32_t flash_id; esp_rom_opiflash_exec_cmd(1, SPI_FLASH_FASTRD_MODE, CMD_RDID, 8, 0, 0, 0, NULL, 0, (uint8_t *)&flash_id, 24, ESP_ROM_OPIFLASH_SEL_CS0, false); uint8_t flid_lowbyte = (flash_id >> 16) & 0xFF; return ((flid_lowbyte >= 0x19 && flid_lowbyte < 0x30) || (flid_lowbyte >= 0x39)); // See DETECTED_FLASH_SIZES in esptool } #endif // ESP32S3 static void stub_handle_rx_byte(char byte) { int16_t r = SLIP_recv_byte(byte, (slip_state_t *)&ub.state); if (r >= 0) { ub.reading_buf[ub.read++] = (uint8_t) r; if (ub.read == MAX_WRITE_BLOCK+64) { /* shouldn't happen unless there are data errors */ r = SLIP_FINISHED_FRAME; } } if (r == SLIP_FINISHED_FRAME) { /* end of frame, set 'command' to be processed by main thread */ if(ub.reading_buf == ub.buf_a) { ub.command = (esp_command_req_t *)ub.buf_a; ub.reading_buf = ub.buf_b; } else { ub.command = (esp_command_req_t *)ub.buf_b; ub.reading_buf = ub.buf_a; } ub.read = 0; } } static esp_command_error verify_data_len(esp_command_req_t *command, uint8_t len) { return (command->data_len == len) ? ESP_OK : ESP_BAD_DATA_LEN; } void cmd_loop() { while(1) { /* Wait for a command */ while(ub.command == NULL) { stub_io_idle_hook(); } esp_command_req_t *command = ub.command; ub.command = NULL; /* provide easy access for 32-bit data words */ uint32_t *data_words = (uint32_t *)command->data_buf; /* Send command response header */ esp_command_response_t resp = { .resp = 1, .op_ret = command->op, .len_ret = 2, /* esptool.py checks this length */ .value = 0, }; /* Some commands need to set resp.len_ret or resp.value before it is sent back */ switch(command->op) { case ESP_READ_REG: if (command->data_len == 4) { resp.value = READ_REG(data_words[0]); } break; case ESP_FLASH_VERIFY_MD5: resp.len_ret = 16 + 2; /* Will sent 16 bytes of data with MD5 value */ break; #if ESP32S2_OR_LATER case ESP_GET_SECURITY_INFO: resp.len_ret = SECURITY_INFO_BYTES; /* Buffer size varies */ break; #endif // ESP32S2_OR_LATER default: break; } /* Send the command response */ SLIP_send_frame_delimiter(); SLIP_send_frame_data_buf(&resp, sizeof(esp_command_response_t)); if(command->data_len > MAX_WRITE_BLOCK+16) { SLIP_send_frame_data(ESP_BAD_DATA_LEN); SLIP_send_frame_data(0xEE); SLIP_send_frame_delimiter(); continue; } /* ... ESP_FLASH_VERIFY_MD5 and ESP_GET_SECURITY_INFO will insert * in-frame response data between here and when we send the * status bytes at the end of the frame */ esp_command_error error = ESP_CMD_NOT_IMPLEMENTED; int status = 0; /* First stage of command processing - before sending error/status */ switch (command->op) { case ESP_SYNC: /* Bootloader responds to the SYNC request with eight identical SYNC responses. Stub flasher should react * the same way so SYNC could be possible with the flasher stub as well. This helps in cases when the chip * cannot be reset and the flasher stub keeps running. */ error = verify_data_len(command, 36); if (error == ESP_OK) { /* resp.value remains 0 which esptool.py can use to detect the flasher stub */ resp.value = 0; for (int i = 0; i < 7; ++i) { SLIP_send_frame_data(error); SLIP_send_frame_data(status); SLIP_send_frame_delimiter(); /* end the previous frame */ SLIP_send_frame_delimiter(); /* start new frame */ SLIP_send_frame_data_buf(&resp, sizeof(esp_command_response_t)); } /* The last frame is ended outside of the "switch case" at the same place regular one-response frames are * ended. */ } break; #if ESP32S2_OR_LATER case ESP_GET_SECURITY_INFO: error = verify_data_len(command, 0) || handle_get_security_info(); break; #endif // ESP32S2_OR_LATER case ESP_ERASE_FLASH: error = verify_data_len(command, 0) || SPIEraseChip(); break; case ESP_ERASE_REGION: /* Params for ERASE_REGION are addr, len */ error = verify_data_len(command, 8) || handle_flash_erase(data_words[0], data_words[1]); break; case ESP_SET_BAUD: /* ESP_SET_BAUD sends two args, new and old baud rates */ error = verify_data_len(command, 8); /* actual baud setting happens after we send the reply */ break; case ESP_READ_FLASH: error = verify_data_len(command, 16); /* actual data is sent after we send the reply */ break; case ESP_FLASH_VERIFY_MD5: /* unsure why the MD5 command has 4 params but we only pass 2 of them, but this is in ESP32 ROM so we can't mess with it. */ error = verify_data_len(command, 16) || handle_flash_get_md5sum(data_words[0], data_words[1]); break; case ESP_FLASH_BEGIN: /* parameters (interpreted differently to ROM flasher): 0 - erase_size (used as total size to write) 1 - num_blocks (ignored) 2 - block_size (should be MAX_WRITE_BLOCK, relies on num_blocks * block_size >= erase_size) 3 - offset (used as-is) */ if (command->data_len == 16 && data_words[2] > MAX_WRITE_BLOCK) { error = ESP_BAD_BLOCKSIZE; } else { error = verify_data_len(command, 16) || handle_flash_begin(data_words[0], data_words[3]); } break; case ESP_FLASH_DEFLATED_BEGIN: /* parameters: 0 - uncompressed size 1 - num_blocks (based on compressed size) 2 - block_size (should be MAX_WRITE_BLOCK, total bytes over serial = num_blocks * block_size) 3 - offset (used as-is) */ if (command->data_len == 16 && data_words[2] > MAX_WRITE_BLOCK) { error = ESP_BAD_BLOCKSIZE; } else { error = verify_data_len(command, 16) || handle_flash_deflated_begin(data_words[0], data_words[1] * data_words[2], data_words[3]); } break; case ESP_FLASH_DATA: case ESP_FLASH_DEFLATED_DATA: #if !ESP8266 case ESP_FLASH_ENCRYPT_DATA: #endif /* ACK DATA commands immediately, then process them a few lines down, allowing next command to buffer */ if(is_in_flash_mode()) { error = get_flash_error(); int payload_len = command->data_len - 16; if (data_words[0] != payload_len) { /* First byte of data payload header is length (repeated) as a word */ error = ESP_BAD_DATA_LEN; } uint8_t data_checksum = calculate_checksum(command->data_buf + 16, payload_len); if (data_checksum != command->checksum) { error = ESP_BAD_DATA_CHECKSUM; } } else { error = ESP_NOT_IN_FLASH_MODE; } break; case ESP_FLASH_END: case ESP_FLASH_DEFLATED_END: error = handle_flash_end(); break; case ESP_SPI_SET_PARAMS: /* data params: fl_id, total_size, block_size, sector_Size, page_size, status_mask */ error = verify_data_len(command, 24) || handle_spi_set_params(data_words, &status); break; case ESP_SPI_ATTACH: /* parameter is 'hspi mode' (0, 1 or a pin mask for ESP32. Ignored on ESP8266.) */ error = verify_data_len(command, 4) || handle_spi_attach(data_words[0]); break; case ESP_WRITE_REG: /* The write_reg command can pass multiple write operations in a sequence */ if (command->data_len % sizeof(write_reg_args_t) != 0) { error = ESP_BAD_DATA_LEN; } else { error = handle_write_reg((const write_reg_args_t *)data_words, command->data_len/sizeof(write_reg_args_t)); } break; case ESP_READ_REG: /* actual READ_REG operation happens higher up */ error = verify_data_len(command, 4); break; case ESP_MEM_BEGIN: error = verify_data_len(command, 16) || handle_mem_begin(data_words[0], data_words[3]); break; case ESP_MEM_DATA: error = handle_mem_data(command->data_buf + 16, command->data_len - 16); break; case ESP_MEM_END: error = verify_data_len(command, 8) || handle_mem_finish(); break; case ESP_RUN_USER_CODE: /* Returning from here will run user code, ie standard boot process This command does not send a response. */ return; } SLIP_send_frame_data(error); SLIP_send_frame_data(status); SLIP_send_frame_delimiter(); /* Some commands need to do things after after sending this response */ if (error == ESP_OK) { switch(command->op) { case ESP_SET_BAUD: stub_io_set_baudrate(data_words[1], data_words[0]); break; case ESP_READ_FLASH: /* args are: offset, length, block_size, max_in_flight */ handle_flash_read(data_words[0], data_words[1], data_words[2], data_words[3]); break; case ESP_FLASH_DATA: /* drop into flashing mode, discard 16 byte payload header */ handle_flash_data(command->data_buf + 16, command->data_len - 16); break; #if !ESP8266 case ESP_FLASH_ENCRYPT_DATA: /* write encrypted data */ handle_flash_encrypt_data(command->data_buf + 16, command->data_len -16); break; #endif case ESP_FLASH_DEFLATED_DATA: handle_flash_deflated_data(command->data_buf + 16, command->data_len - 16); break; case ESP_FLASH_DEFLATED_END: case ESP_FLASH_END: /* passing 0 as parameter for ESP_FLASH_END means reboot now */ if (data_words[0] == 0) { /* Flush the FLASH_END response before rebooting */ stub_tx_flush(); ets_delay_us(10000); #if USE_MAX_CPU_FREQ reset_cpu_freq(); #endif // USE_MAX_CPU_FREQ software_reset(); } break; case ESP_MEM_END: if (data_words[1] != 0) { void (*entrypoint_fn)(void) = (void (*))data_words[1]; /* Make sure the command response has been flushed out of the UART before we run the new code */ stub_tx_flush(); ets_delay_us(1000); /* this is a little different from the ROM loader, which exits the loader routine and _then_ calls this function. But for our purposes so far, having a bit of extra stuff on the stack doesn't really matter. */ #if USE_MAX_CPU_FREQ reset_cpu_freq(); #endif // USE_MAX_CPU_FREQ entrypoint_fn(); } break; } } } } extern uint32_t _bss_start; extern uint32_t _bss_end; void __attribute__((used)) stub_main(); #ifdef ESP8266 __asm__ ( ".global stub_main_8266\n" ".literal_position\n" ".align 4\n" "stub_main_8266:\n" /* ESP8266 wrapper for "stub_main()" manipulates the return address in * a0, so 'return' from here runs user code. * * After setting a0, we jump directly to stub_main_inner() which is a * normal C function * * Adapted from similar approach used by Cesanta Software for ESP8266 * flasher stub. * */ "movi a0, 0x400010a8;" "j stub_main;"); #endif /* This function is called from stub_main, with return address reset to point to user code. */ void stub_main() { const uint32_t greeting = 0x4941484f; /* OHAI */ /* This points to stub_main now, clear for next boot. */ ets_set_user_start(0); /* Increase CPU frequency and flashing speed if supported. */ #if USE_MAX_CPU_FREQ set_max_cpu_freq(); #endif // USE_MAX_CPU_FREQ /* Disable all watchdogs to prevent the chip from resetting during longer operations. */ #if WITH_USB_JTAG_SERIAL disable_watchdogs(); #endif // WITH_USB_JTAG_SERIAL /* Zero the bss region. */ for(uint32_t *p = &_bss_start; p < &_bss_end; p++) { *p = 0; } /* Send the OHAI greeting, stub will be reported as running. */ SLIP_send(&greeting, 4); /* Configure the interrupts for receiving data from esptool on the host. */ ub.reading_buf = ub.buf_a; stub_io_init(&stub_handle_rx_byte); /* Configure default SPI flash functionality. Can be overridden later by esptool.py. */ #ifdef ESP8266 SelectSpiFunction(); spi_flash_attach(); #else #if SUPPORT_CONFIG_SPI uint32_t spiconfig = ets_efuse_get_spiconfig(); #else uint32_t spiconfig = 0; #endif // SUPPORT_CONFIG_SPI uint32_t strapping = READ_REG(GPIO_STRAP_REG); /* If GPIO1 (U0TXD) is pulled low and no other boot mode is set in efuse, assume HSPI flash mode (same as normal boot) */ if (spiconfig == 0 && (strapping & 0x1c) == 0x08) { spiconfig = 1; /* HSPI flash mode */ } spi_flash_attach(spiconfig, 0); #endif // ESP8266 /* Initialize the OPI flash driver if supported. */ #if ESP32S3 && !ESP32S3BETA2 large_flash_mode = ets_efuse_flash_octal_mode() || flash_larger_than_16mb(); // Initialize OPI flash driver only when flash is detected octal or quad larger than 16MB. // Otherwise, we don't need to initialize such a driver if (large_flash_mode) { static const esp_rom_opiflash_def_t flash_driver = OPIFLASH_DRIVER(); esp_rom_opiflash_legacy_driver_init(&flash_driver); esp_rom_opiflash_wait_idle(); } #endif //ESP32S3 && !ESP32S3BETA2 SPIParamCfg(0, FLASH_MAX_SIZE, FLASH_BLOCK_SIZE, FLASH_SECTOR_SIZE, FLASH_PAGE_SIZE, FLASH_STATUS_MASK); /* Configurations are done, now run the loop to receive and handle commands. */ cmd_loop(); /* If cmd_loop returns, it's due to ESP_RUN_USER_CODE command. */ /* Decrease CPU frequency back to the saved value before the stub flasher returns. */ #if USE_MAX_CPU_FREQ reset_cpu_freq(); #endif // USE_MAX_CPU_FREQ return; }