From 6dae5b206fbbb6d457714c6f01473f7ff228898a Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 27 Aug 2018 08:12:28 +0800 Subject: [PATCH] reset_reason: fix setting wake stub entry point to 0x80000000 esp_reset_reason_init would check for reset reason hint, and unconditionally set RTC_RESET_CAUSE_REG (which is also RTC_ENTRY_ADDR_REG) to hint value 0, i.e. 0x80000000. However the ROM code treats this value as valid deep sleep wake stub entry point, and tries to jump to it. Clear RTC_RESET_CAUSE_REG only if it contained a valid reset reason hint, and simply set the register value to 0 when doing so. Also add a check to esp_get_deep_sleep_wake_stub function that deep sleep wake stub entry address must be in IRAM. Reported in https://esp32.com/viewtopic.php?f=13&t=6919. --- components/esp32/reset_reason.c | 14 +++++- components/esp32/sleep_modes.c | 9 ++-- components/esp32/test/test_sleep.c | 68 ++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/components/esp32/reset_reason.c b/components/esp32/reset_reason.c index 191271df0..b43bc8bc7 100644 --- a/components/esp32/reset_reason.c +++ b/components/esp32/reset_reason.c @@ -17,6 +17,8 @@ #include "rom/rtc.h" #include "soc/rtc_cntl_reg.h" +static void esp_reset_reason_clear_hint(); + static esp_reset_reason_t s_reset_reason; static esp_reset_reason_t get_reset_reason(RESET_REASON rtc_reset_reason, esp_reset_reason_t reset_reason_hint) @@ -69,9 +71,12 @@ static esp_reset_reason_t get_reset_reason(RESET_REASON rtc_reset_reason, esp_re static void __attribute__((constructor)) esp_reset_reason_init(void) { + esp_reset_reason_t hint = esp_reset_reason_get_hint(); s_reset_reason = get_reset_reason(rtc_get_reset_reason(PRO_CPU_NUM), - esp_reset_reason_get_hint()); - esp_reset_reason_set_hint(ESP_RST_UNKNOWN); + hint); + if (hint != ESP_RST_UNKNOWN) { + esp_reset_reason_clear_hint(); + } } esp_reset_reason_t esp_reset_reason(void) @@ -114,3 +119,8 @@ esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void) } return (esp_reset_reason_t) low; } +static void esp_reset_reason_clear_hint() +{ + REG_WRITE(RTC_RESET_CAUSE_REG, 0); +} + diff --git a/components/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index 2fda37a5d..ac9ea70dc 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -103,11 +103,14 @@ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void) REG_WRITE(RTC_MEMORY_CRC_REG, stored_crc); _lock_release(&lock_rtc_memory_crc); - if(stored_crc == calc_crc) { - return (esp_deep_sleep_wake_stub_fn_t)REG_READ(RTC_ENTRY_ADDR_REG); - } else { + if(stored_crc != calc_crc) { return NULL; } + esp_deep_sleep_wake_stub_fn_t stub_ptr = (esp_deep_sleep_wake_stub_fn_t) REG_READ(RTC_ENTRY_ADDR_REG); + if (!esp_ptr_executable(stub_ptr)) { + return NULL; + } + return stub_ptr; } void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub) diff --git a/components/esp32/test/test_sleep.c b/components/esp32/test/test_sleep.c index 2212de3c4..7eb504226 100644 --- a/components/esp32/test/test_sleep.c +++ b/components/esp32/test/test_sleep.c @@ -202,6 +202,74 @@ TEST_CASE("enter deep sleep on APP CPU and wake up using timer", "[deepsleep][re } #endif +static void do_deep_sleep() +{ + esp_sleep_enable_timer_wakeup(100000); + esp_deep_sleep_start(); +} + +static void check_sleep_reset_and_sleep() +{ + TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); + esp_sleep_enable_timer_wakeup(100000); + esp_deep_sleep_start(); +} + +static void check_sleep_reset() +{ + TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); +} + +TEST_CASE_MULTIPLE_STAGES("enter deep sleep more than once", "[deepsleep][reset=DEEPSLEEP_RESET,DEEPSLEEP_RESET,DEEPSLEEP_RESET]", + do_deep_sleep, + check_sleep_reset_and_sleep, + check_sleep_reset_and_sleep, + check_sleep_reset); + +static void do_abort() +{ + abort(); +} + +static void check_abort_reset_and_sleep() +{ + TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason()); + esp_sleep_enable_timer_wakeup(100000); + esp_deep_sleep_start(); +} + +TEST_CASE_MULTIPLE_STAGES("enter deep sleep after abort", "[deepsleep][reset=abort,SW_CPU_RESET,DEEPSLEEP_RESET]", + do_abort, + check_abort_reset_and_sleep, + check_sleep_reset); + +static RTC_DATA_ATTR uint32_t s_wake_stub_var; + +static RTC_IRAM_ATTR void wake_stub() +{ + esp_default_wake_deep_sleep(); + s_wake_stub_var = (uint32_t) &wake_stub; +} + +static void prepare_wake_stub() +{ + esp_set_deep_sleep_wake_stub(&wake_stub); + esp_sleep_enable_timer_wakeup(100000); + esp_deep_sleep_start(); +} + +static void check_wake_stub() +{ + TEST_ASSERT_EQUAL(ESP_RST_DEEPSLEEP, esp_reset_reason()); + TEST_ASSERT_EQUAL_HEX32((uint32_t) &wake_stub, s_wake_stub_var); + /* ROM code clears wake stub entry address */ + TEST_ASSERT_NULL(esp_get_deep_sleep_wake_stub()); +} + +TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub", "[deepsleep][reset=DEEPSLEEP_RESET]", + prepare_wake_stub, + check_wake_stub); + TEST_CASE("wake up using ext0 (13 high)", "[deepsleep][ignore]") {