Merge branch 'bugfix/esptool_write_protect' into 'master'

Fix flash write protect bug

As reported in github #50 and on forum.

Incorporates other esptool.py changes:
197ba605...5c6962e8


See merge request !144
This commit is contained in:
Angus Gratton
2016-10-24 09:58:46 +08:00
11 changed files with 162 additions and 13 deletions

View File

@@ -8,7 +8,7 @@
# basically runs Make in the src/ directory but it needs to zero some variables # basically runs Make in the src/ directory but it needs to zero some variables
# the ESP-IDF project.mk makefile exports first, to not let them interfere. # the ESP-IDF project.mk makefile exports first, to not let them interfere.
# #
ifeq ("$(IS_BOOTLOADER_BUILD)","") ifndef IS_BOOTLOADER_BUILD
BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH) BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader) BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)

View File

@@ -4,12 +4,13 @@
# #
PROJECT_NAME := bootloader PROJECT_NAME := bootloader
COMPONENTS := esptool_py bootloader log COMPONENTS := esptool_py bootloader log spi_flash
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included. # The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
# #
# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op # IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op
IS_BOOTLOADER_BUILD := 1 IS_BOOTLOADER_BUILD := 1
export IS_BOOTLOADER_BUILD
#We cannot include the esp32 component directly but we need its includes. #We cannot include the esp32 component directly but we need its includes.
#This is fixed by adding CFLAGS from Makefile.projbuild #This is fixed by adding CFLAGS from Makefile.projbuild

View File

@@ -51,7 +51,7 @@ enum {
SPI_SPEED_20M, SPI_SPEED_20M,
SPI_SPEED_80M = 0xF SPI_SPEED_80M = 0xF
}; };
/*suppport flash size in esp32 */ /*supported flash sizes*/
enum { enum {
SPI_SIZE_1MB = 0, SPI_SIZE_1MB = 0,
SPI_SIZE_2MB, SPI_SIZE_2MB,

View File

@@ -58,6 +58,7 @@ void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr,
uint32_t irom_load_addr, uint32_t irom_load_addr,
uint32_t irom_size, uint32_t irom_size,
uint32_t entry_addr); uint32_t entry_addr);
static void update_flash_config(struct flash_hdr* pfhdr);
void IRAM_ATTR call_start_cpu0() void IRAM_ATTR call_start_cpu0()
@@ -258,7 +259,7 @@ void bootloader_main()
memset(&bs, 0, sizeof(bs)); memset(&bs, 0, sizeof(bs));
ESP_LOGI(TAG, "compile time " __TIME__ ); ESP_LOGI(TAG, "compile time " __TIME__ );
/* close watch dog here */ /* disable watch dog here */
REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
SPIUnlock(); SPIUnlock();
@@ -269,6 +270,8 @@ void bootloader_main()
print_flash_info(&fhdr); print_flash_info(&fhdr);
update_flash_config(&fhdr);
if (!load_partition_table(&bs, PARTITION_ADD)) { if (!load_partition_table(&bs, PARTITION_ADD)) {
ESP_LOGE(TAG, "load partition table error!"); ESP_LOGE(TAG, "load partition table error!");
return; return;
@@ -364,7 +367,7 @@ void unpack_load_app(const partition_pos_t* partition)
uint32_t irom_size = 0; uint32_t irom_size = 0;
/* Reload the RTC memory sections whenever a non-deepsleep reset /* Reload the RTC memory sections whenever a non-deepsleep reset
is occuring */ is occurring */
bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET; bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic, ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
@@ -482,6 +485,36 @@ void IRAM_ATTR set_cache_and_start_app(
(*entry)(); (*entry)();
} }
static void update_flash_config(struct flash_hdr* pfhdr)
{
uint32_t size;
switch(pfhdr->spi_size) {
case SPI_SIZE_1MB:
size = 1;
break;
case SPI_SIZE_2MB:
size = 2;
break;
case SPI_SIZE_4MB:
size = 4;
break;
case SPI_SIZE_8MB:
size = 8;
break;
case SPI_SIZE_16MB:
size = 16;
break;
default:
size = 2;
}
Cache_Read_Disable( 0 );
// Set flash chip size
SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
// TODO: set mode
// TODO: set frequency
Cache_Flush(0);
Cache_Read_Enable( 0 );
}
void print_flash_info(struct flash_hdr* pfhdr) void print_flash_info(struct flash_hdr* pfhdr)
{ {

View File

@@ -218,7 +218,7 @@ void SelectSpiFunction(uint32_t ishspi);
void spi_flash_attach(uint32_t ishspi, bool legacy); void spi_flash_attach(uint32_t ishspi, bool legacy);
/** /**
* @brief SPI Read Flash status register. We use CMD 0x05. * @brief SPI Read Flash status register. We use CMD 0x05 (RDSR).
* Please do not call this function in SDK. * Please do not call this function in SDK.
* *
* @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file.
@@ -232,7 +232,7 @@ void spi_flash_attach(uint32_t ishspi, bool legacy);
SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status);
/** /**
* @brief SPI Read Flash status register high 16 bit. We use CMD 0x35. * @brief SPI Read Flash status register bits 8-15. We use CMD 0x35 (RDSR2).
* Please do not call this function in SDK. * Please do not call this function in SDK.
* *
* @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file.
@@ -243,7 +243,7 @@ SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status);
* SPI_FLASH_RESULT_ERR : read error. * SPI_FLASH_RESULT_ERR : read error.
* SPI_FLASH_RESULT_TIMEOUT : read timeout. * SPI_FLASH_RESULT_TIMEOUT : read timeout.
*/ */
SpiFlashOpResult SPI_read_status_high(SpiFlashChip *spi, uint32_t *status); SpiFlashOpResult SPI_read_status_high(uint32_t *status);
/** /**
* @brief Write status to Falsh status register. * @brief Write status to Falsh status register.
@@ -503,6 +503,12 @@ void SPI_Write_Encrypt_Disable(void);
*/ */
SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len);
/** @brief Global SpiFlashChip structure used by ROM functions
*
*/
extern SpiFlashChip g_rom_flashchip;
/** /**
* @} * @}
*/ */

View File

@@ -286,6 +286,7 @@ PROVIDE ( _global_impure_ptr = 0x3ffae0b0 );
PROVIDE ( gmtime = 0x40059848 ); PROVIDE ( gmtime = 0x40059848 );
PROVIDE ( gmtime_r = 0x40059868 ); PROVIDE ( gmtime_r = 0x40059868 );
PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 ); PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 );
PROVIDE ( g_rom_flashchip = 0x3ffae270 );
PROVIDE ( gpio_init = 0x40009c20 ); PROVIDE ( gpio_init = 0x40009c20 );
PROVIDE ( gpio_input_get = 0x40009b88 ); PROVIDE ( gpio_input_get = 0x40009b88 );
PROVIDE ( gpio_input_get_high = 0x40009b9c ); PROVIDE ( gpio_input_get_high = 0x40009b9c );
@@ -1584,6 +1585,8 @@ PROVIDE ( SPIEraseBlock = 0x40062c4c );
PROVIDE ( SPIEraseChip = 0x40062c14 ); PROVIDE ( SPIEraseChip = 0x40062c14 );
PROVIDE ( SPIEraseSector = 0x40062ccc ); PROVIDE ( SPIEraseSector = 0x40062ccc );
PROVIDE ( spi_flash_attach = 0x40062a6c ); PROVIDE ( spi_flash_attach = 0x40062a6c );
/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated
version in the "spi_flash" component */
PROVIDE ( SPILock = 0x400628f0 ); PROVIDE ( SPILock = 0x400628f0 );
PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 ); PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 );
PROVIDE ( spi_modes = 0x3ff99270 ); PROVIDE ( spi_modes = 0x3ff99270 );
@@ -1595,9 +1598,8 @@ PROVIDE ( SPIReadModeCnfig = 0x40062944 );
PROVIDE ( SPI_read_status = 0x4006226c ); PROVIDE ( SPI_read_status = 0x4006226c );
/* This is static function, but can be used, not generated by script*/ /* This is static function, but can be used, not generated by script*/
PROVIDE ( SPI_read_status_high = 0x40062448 ); PROVIDE ( SPI_read_status_high = 0x40062448 );
PROVIDE ( SPIUnlock = 0x400628b0 );
PROVIDE ( SPI_user_command_read = 0x400621b0 ); PROVIDE ( SPI_user_command_read = 0x400621b0 );
PROVIDE ( spi_w25q16 = 0x3ffae270 ); PROVIDE ( SPI_flashchip_data = 0x3ffae270 );
PROVIDE ( SPIWrite = 0x40062d50 ); PROVIDE ( SPIWrite = 0x40062d50 );
/* This is static function, but can be used, not generated by script*/ /* This is static function, but can be used, not generated by script*/
PROVIDE ( SPI_write_enable = 0x40062320 ); PROVIDE ( SPI_write_enable = 0x40062320 );

View File

@@ -94,4 +94,31 @@ config ESPTOOLPY_FLASHFREQ
default "26m" if ESPTOOLPY_FLASHFREQ_26M default "26m" if ESPTOOLPY_FLASHFREQ_26M
default "20m" if ESPTOOLPY_FLASHFREQ_20M default "20m" if ESPTOOLPY_FLASHFREQ_20M
choice ESPTOOLPY_FLASHSIZE
prompt "Flash size"
default ESPTOOLPY_FLASHSIZE_2MB
help
SPI flash size, in megabytes
config ESPTOOLPY_FLASHSIZE_1MB
bool "1 MB"
config ESPTOOLPY_FLASHSIZE_2MB
bool "2 MB"
config ESPTOOLPY_FLASHSIZE_4MB
bool "4 MB"
config ESPTOOLPY_FLASHSIZE_8MB
bool "8 MB"
config ESPTOOLPY_FLASHSIZE_16MB
bool "16 MB"
endchoice
config ESPTOOLPY_FLASHSIZE
string
default "1MB" if ESPTOOLPY_FLASHSIZE_1MB
default "2MB" if ESPTOOLPY_FLASHSIZE_2MB
default "4MB" if ESPTOOLPY_FLASHSIZE_4MB
default "8MB" if ESPTOOLPY_FLASHSIZE_8MB
default "16MB" if ESPTOOLPY_FLASHSIZE_16MB
endmenu endmenu

View File

@@ -4,6 +4,7 @@ ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT)
ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD) ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD)
ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE) ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE)
ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ) ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ)
ESPFLASHSIZE ?= $(CONFIG_ESPTOOLPY_FLASHSIZE)
PYTHON ?= $(call dequote,$(CONFIG_PYTHON)) PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
@@ -15,13 +16,15 @@ ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32 ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE)
# the no-stub argument is temporary until esptool.py fully supports compressed uploads # the no-stub argument is temporary until esptool.py fully supports compressed uploads
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS)
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC) $(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC)
$(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $< $(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $<
flash: all_binaries $(ESPTOOLPY_SRC) flash: all_binaries $(ESPTOOLPY_SRC)
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."

View File

@@ -1,3 +1,8 @@
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
ifdef IS_BOOTLOADER_BUILD
# Bootloader needs updated SPIUnlock from this file
COMPONENT_OBJS := spi_flash_rom_patch.o
endif
include $(IDF_PATH)/make/component_common.mk include $(IDF_PATH)/make/component_common.mk

View File

@@ -0,0 +1,72 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rom/spi_flash.h"
#include "soc/spi_reg.h"
static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */
#define SPI_IDX 1
#define OTH_IDX 0
extern SpiFlashChip SPI_flashchip_data;
static void IRAM_ATTR Wait_SPI_Idle(void)
{
/* Wait for SPI state machine to be idle */
while((REG_READ(SPI_EXT2_REG(SPI_IDX)) & SPI_ST)) {
}
while(REG_READ(SPI_EXT2_REG(OTH_IDX)) & SPI_ST) {
}
}
/* Modified version of SPIUnlock() that replaces version in ROM.
This works around a bug where SPIUnlock sometimes reads the wrong
high status byte (RDSR2 result) and then copies it back to the
flash status, which can cause the CMP bit or Status Register
Protect bit to become set.
Like other ROM SPI functions, this function is not designed to be
called directly from an RTOS environment without taking precautions
about interrupts, CPU coordination, flash mapping. However some of
the functions in esp_spi_flash.c call it.
*/
SpiFlashOpResult IRAM_ATTR SPIUnlock(void)
{
uint32_t status;
Wait_SPI_Idle();
if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) {
return SPI_FLASH_RESULT_ERR;
}
/* Clear all bits except QIE, if it is set.
(This is different from ROM SPIUnlock, which keeps all bits as-is.)
*/
status &= STATUS_QIE_BIT;
Wait_SPI_Idle();
REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN);
while(REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) {
}
Wait_SPI_Idle();
SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
if (SPI_write_status(&SPI_flashchip_data, status) != SPI_FLASH_RESULT_OK) {
return SPI_FLASH_RESULT_ERR;
}
return SPI_FLASH_RESULT_OK;
}