Merge branch 'bugfix/fix_wrong_frame_ptr_after_wake_restore' into 'master'

bugfix: fix wrong RvCoreCriticalSleepFrame ptr value after wake restore

See merge request espressif/esp-idf!23113
This commit is contained in:
Wu Zheng Hui 2023-04-14 13:22:24 +08:00
commit 98849634b3
8 changed files with 78 additions and 10 deletions

View File

@ -14,6 +14,7 @@
#include "esp_check.h" #include "esp_check.h"
#include "esp_sleep.h" #include "esp_sleep.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_crc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
@ -25,6 +26,12 @@
#include "hal/rtc_hal.h" #include "hal/rtc_hal.h"
#endif #endif
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
#include "esp_private/system_internal.h"
#include "hal/clk_gate_ll.h"
#include "hal/uart_hal.h"
#endif
#include "soc/rtc_periph.h" #include "soc/rtc_periph.h"
#ifdef CONFIG_IDF_TARGET_ESP32S3 #ifdef CONFIG_IDF_TARGET_ESP32S3
@ -557,6 +564,32 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *
} }
} }
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
static void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
{
*(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size);
}
static void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr)
{
if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){
// resume uarts
for (int i = 0; i < SOC_UART_NUM; ++i) {
#ifndef CONFIG_IDF_TARGET_ESP32
if (!periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) {
continue;
}
#endif
uart_ll_force_xon(i);
}
/* Since it is still in the critical now, use ESP_EARLY_LOG */
ESP_EARLY_LOGE(TAG, "Sleep retention frame is corrupted");
esp_restart_noos();
}
}
#endif
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_save(void); extern RvCoreCriticalSleepFrame * rv_core_critical_regs_save(void);
extern RvCoreCriticalSleepFrame * rv_core_critical_regs_restore(void); extern RvCoreCriticalSleepFrame * rv_core_critical_regs_restore(void);
typedef uint32_t (* sleep_cpu_entry_cb_t)(uint32_t, uint32_t, uint32_t, bool); typedef uint32_t (* sleep_cpu_entry_cb_t)(uint32_t, uint32_t, uint32_t, bool);
@ -566,9 +599,18 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep,
{ {
RvCoreCriticalSleepFrame * frame = rv_core_critical_regs_save(); RvCoreCriticalSleepFrame * frame = rv_core_critical_regs_save();
if ((frame->pmufunc & 0x3) == 0x1) { if ((frame->pmufunc & 0x3) == 0x1) {
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
/* Minus 2 * sizeof(long) is for bypass `pmufunc` and `frame_crc` field */
update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
REG_WRITE(LIGHT_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); REG_WRITE(LIGHT_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore);
return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); return (*goto_sleep)(wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
} }
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
else {
validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc));
}
#endif
return ESP_OK; return ESP_OK;
} }
@ -588,8 +630,17 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin
cpu_domain_dev_regs_save(s_cpu_retention.retent.cache_config_frame); cpu_domain_dev_regs_save(s_cpu_retention.retent.cache_config_frame);
RvCoreNonCriticalSleepFrame *frame = rv_core_noncritical_regs_save(); RvCoreNonCriticalSleepFrame *frame = rv_core_noncritical_regs_save();
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
/* Minus sizeof(long) is for bypass `frame_crc` field */
update_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp); esp_err_t err = do_cpu_retention(goto_sleep, wakeup_opt, reject_opt, lslp_mem_inf_fpu, dslp);
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
validate_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc));
#endif
rv_core_noncritical_regs_restore(frame); rv_core_noncritical_regs_restore(frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame); cpu_domain_dev_regs_restore(s_cpu_retention.retent.cache_config_frame);
cpu_domain_dev_regs_restore(s_cpu_retention.retent.intpri_frame); cpu_domain_dev_regs_restore(s_cpu_retention.retent.intpri_frame);

View File

@ -53,11 +53,12 @@ rv_core_critical_regs_save:
sw t2, RV_SLP_CTX_T2(t0) sw t2, RV_SLP_CTX_T2(t0)
sw s0, RV_SLP_CTX_S0(t0) sw s0, RV_SLP_CTX_S0(t0)
sw s1, RV_SLP_CTX_S1(t0) sw s1, RV_SLP_CTX_S1(t0)
sw a0, RV_SLP_CTX_A0(t0)
/* !! WARNING, do not use the a0 register below, a0 carries important sleep /* a0 is caller saved, so it does not need to be saved, but it should be the
* information and will be returned as the return value !! */ pointer value of RvCoreCriticalSleepFrame for return.
*/
mv a0, t0 mv a0, t0
sw a0, RV_SLP_CTX_A0(t0)
sw a1, RV_SLP_CTX_A1(t0) sw a1, RV_SLP_CTX_A1(t0)
sw a2, RV_SLP_CTX_A2(t0) sw a2, RV_SLP_CTX_A2(t0)

View File

@ -2,6 +2,6 @@
components/esp_pm/test_apps/esp_pm: components/esp_pm/test_apps/esp_pm:
disable: disable:
- if: IDF_TARGET in ["esp32c6", "esp32h2"] - if: IDF_TARGET in ["esp32h2"]
temporary: true temporary: true
reason: Not supported yet reason: Not supported yet

View File

@ -85,6 +85,14 @@ menu "Power Management"
bool bool
default n default n
config PM_CHECK_SLEEP_RETENTION_FRAME
bool
depends on PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
default n if !IDF_CI_BUILD
help
This option is invisible to users, and it is only used for ci testing,
enabling it in the application will increase the sleep and wake-up time overhead
config PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP config PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
bool "Power down CPU in light sleep" bool "Power down CPU in light sleep"
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6 depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C6

View File

@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |

View File

@ -62,7 +62,7 @@ static void switch_freq(int mhz)
} }
} }
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
static const int test_freqs[] = {40, CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, 80, 40, 80, 10, 80, 20, 40}; static const int test_freqs[] = {40, CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, 80, 40, 80, 10, 80, 20, 40};
#elif CONFIG_IDF_TARGET_ESP32C2 #elif CONFIG_IDF_TARGET_ESP32C2
static const int test_freqs[] = {CONFIG_XTAL_FREQ, CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, 80, CONFIG_XTAL_FREQ, 80, static const int test_freqs[] = {CONFIG_XTAL_FREQ, CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, 80, CONFIG_XTAL_FREQ, 80,

View File

@ -5,9 +5,9 @@ import pytest
from pytest_embedded import Dut from pytest_embedded import Dut
CONFIGS = [ CONFIGS = [
pytest.param('default', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32c6', 'esp32h2'], reason='c6/h2 support TBD')]), pytest.param('default', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32h2'], reason='h2 support TBD')]),
pytest.param('limits', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32c6', 'esp32h2'], reason='c6/h2 support TBD')]), pytest.param('limits', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32h2'], reason='h2 support TBD')]),
pytest.param('options', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32c6', 'esp32h2'], reason='c6/h2 support TBD')]), pytest.param('options', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32h2'], reason='h2 support TBD')]),
] ]

View File

@ -7,6 +7,8 @@
#ifndef __RVSLEEP_FRAMES_H__ #ifndef __RVSLEEP_FRAMES_H__
#define __RVSLEEP_FRAMES_H__ #define __RVSLEEP_FRAMES_H__
#include "sdkconfig.h"
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */ /* Align a value up to nearest n-byte boundary, where n is a power of 2. */
#define ALIGNUP(n, val) (((val) + (n) - 1) & -(n)) #define ALIGNUP(n, val) (((val) + (n) - 1) & -(n))
@ -86,6 +88,9 @@ STRUCT_BEGIN
* to sleep or has just been awakened. We use the * to sleep or has just been awakened. We use the
* lowest 2 bits as indication infomation, 3 means * lowest 2 bits as indication infomation, 3 means
* being awakened, 1 means going to sleep */ * being awakened, 1 means going to sleep */
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
STRUCT_FIELD (long, 4, RV_SLP_CSF_CTX_CRC, frame_crc) /* Used to check RvCoreCriticalSleepFrame integrity */
#endif
STRUCT_END(RvCoreCriticalSleepFrame) STRUCT_END(RvCoreCriticalSleepFrame)
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) #if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
@ -148,6 +153,9 @@ STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OEN, ugpio_oen) STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OEN, ugpio_oen)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_IN, ugpio_in) STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_IN, ugpio_in)
STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OUT, ugpio_out) STRUCT_FIELD (long, 4, RV_SLP_CTX_UGPIO_OUT, ugpio_out)
#if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME
STRUCT_FIELD (long, 4, RV_SLP_NCSF_CTX_CRC, frame_crc) /* Used to check RvCoreNonCriticalSleepFrame integrity */
#endif
STRUCT_END(RvCoreNonCriticalSleepFrame) STRUCT_END(RvCoreNonCriticalSleepFrame)
#endif /* #ifndef __RVSLEEP_FRAMES_H__ */ #endif /* #ifndef __RVSLEEP_FRAMES_H__ */