mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(cpu_region_protect): Extend PMP memprot for ESP32-P4 V3
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
#include "esp_private/esp_psram_extram.h"
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
|
||||
#include "soc/chip_revision.h"
|
||||
#include "hal/config.h"
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
// Without L bit set
|
||||
#define CONDITIONAL_NONE 0x0
|
||||
@@ -82,70 +85,160 @@ static void esp_cpu_configure_invalid_regions(void)
|
||||
PMA_RESET_AND_ENTRY_SET_TOR(15, UINT32_MAX, PMA_TOR | PMA_NONE);
|
||||
}
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
*
|
||||
* 1) Note: ESP32-P4 CPU support overlapping PMP regions, configuration is based on static priority
|
||||
* feature (lowest numbered entry has highest priority).
|
||||
*
|
||||
* 2) ESP32-P4 supports 16 PMA regions so we use this feature to block the invalid address ranges.
|
||||
* However the entries are not sufficient to block all reserved memory ranges and the excluded sections are:
|
||||
* a. Region between LP ROM and LP SRAM
|
||||
* b. Region between LP peripherals and External flash (direct access)
|
||||
* c. Region between External flash (direct access) and External RAM (direct access)
|
||||
* d. Region between External RAM (direct access) and HP ROM (direct access)
|
||||
* e. Region between HP ROM (direct access) and HP L2MEM (direct access)
|
||||
*
|
||||
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
|
||||
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
|
||||
* which can be used to provide more granular access
|
||||
*
|
||||
* 4) Entries are grouped in order with some static asserts to try and verify everything is
|
||||
* correct.
|
||||
*
|
||||
* 5) No explicit permission specified in PMP (default all permissions) for following regions due to
|
||||
* limited entries:
|
||||
* a. External RAM
|
||||
* b. LP ROM, LP Peripherals, LP SRAM
|
||||
* c. External flash, External RAM, HP ROM, HP L2MEM (direct access)
|
||||
*/
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
// Helper macro to set both cached and non-cached PMP entries with the same permissions
|
||||
#define PMP_ENTRY_SET_CACHED_AND_UNCACHED(cached_entry, non_cached_entry, addr, perm) \
|
||||
do { \
|
||||
PMP_RESET_AND_ENTRY_SET(cached_entry, addr, perm); \
|
||||
PMP_RESET_AND_ENTRY_SET(non_cached_entry, CACHE_LL_L2MEM_NON_CACHE_ADDR(addr), perm); \
|
||||
} while(0)
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. Application build with CONFIG_ESP_SYSTEM_MEMPROT enabled
|
||||
* - We split the SRAM into IRAM and DRAM such that IRAM region cannot be written to
|
||||
* and DRAM region cannot be executed. We use _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. Application build with CONFIG_ESP_SYSTEM_MEMPROT disabled
|
||||
* - The IRAM-DRAM split is not enabled so we just need to ensure that access to only valid address ranges are successful
|
||||
* so for that we set PMP to cover entire valid IRAM and DRAM region.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 4. CPU is in OCD debug mode
|
||||
* - The IRAM-DRAM split is not enabled so that OpenOCD can write and execute from IRAM.
|
||||
* We set PMP to cover entire valid IRAM and DRAM region.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*/
|
||||
static void esp_cpu_configure_region_protection_rev_v3(void)
|
||||
{
|
||||
const unsigned NONE = PMP_L;
|
||||
__attribute__((unused)) const unsigned R = PMP_L | PMP_R;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
esp_cpu_configure_invalid_regions();
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
// 2. HP-CPU TCM
|
||||
// The default memory permissions are RWX and TCM should be RWX, so we can skip configuring it
|
||||
|
||||
// 3. CPU Peripherals
|
||||
const uint32_t pmpaddr1 = PMPADDR_NAPOT(CPU_PERIPH_LOW, CPU_PERIPH_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(1, pmpaddr1, PMP_NAPOT | RW);
|
||||
_Static_assert(CPU_PERIPH_LOW < CPU_PERIPH_HIGH, "Invalid CPU peripheral region");
|
||||
|
||||
// 4. I/D-ROM
|
||||
const uint32_t pmpaddr2 = PMPADDR_NAPOT(SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(2, pmpaddr2, PMP_NAPOT | RX);
|
||||
|
||||
const uint32_t pmpaddr3 = PMPADDR_NAPOT(CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_MASK_LOW), CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_MASK_HIGH));
|
||||
PMP_RESET_AND_ENTRY_SET(3, pmpaddr3, PMP_NAPOT | RX);
|
||||
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
|
||||
|
||||
// 5. IRAM and DRAM
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
// Anti-FI check that cpu is really in ocd mode
|
||||
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
|
||||
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(4, 6, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(5, 7, SOC_IRAM_HIGH, PMP_TOR | RWX);
|
||||
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
} else {
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _iram_text_end;
|
||||
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(4, 7, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(5, 8, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(6, 9, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(4, 6, SOC_IRAM_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(5, 7, SOC_IRAM_HIGH, PMP_TOR | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
const uint32_t page_aligned_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end));
|
||||
__attribute__((unused)) const uint32_t page_aligned_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
// 6. I_EXTRAM / D_EXTRAM (SPIRAM)
|
||||
#if CONFIG_SPIRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
|
||||
const size_t available_psram_heap = esp_psram_get_heap_size_to_protect();
|
||||
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(10, 15, SOC_EXTRAM_LOW, NONE);
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(12, 17, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(13, 18, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(14, 19, ALIGN_UP((uint32_t)(&_rodata_reserved_end) + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
|
||||
#elif CONFIG_SPIRAM_FETCH_INSTRUCTIONS
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(12, 17, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(13, 18, ALIGN_UP(page_aligned_irom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
|
||||
#elif CONFIG_SPIRAM_RODATA
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(12, 17, ALIGN_UP((uint32_t)(&_rodata_reserved_end) + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
|
||||
#else
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, ALIGN_UP(SOC_EXTRAM_LOW + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
#endif
|
||||
#endif /* CONFIG_SPIRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
|
||||
// ESP32-P4 V3's 24th PMP entry cannot be used as a TOR entry // DIG-752
|
||||
// 7. I_Cache / D_Cache (flash)
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(20, 24, SOC_IROM_LOW, NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(21, 25, page_aligned_irom_resv_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(22, 26, page_aligned_drom_resv_end, PMP_TOR | R);
|
||||
|
||||
#else
|
||||
#if CONFIG_SPIRAM
|
||||
const uint32_t pmpaddr10 = PMPADDR_NAPOT(SOC_EXTRAM_LOW, SOC_EXTRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(10, pmpaddr10, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_EXTRAM_LOW), CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_EXTRAM_HIGH));
|
||||
PMP_RESET_AND_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_EXTRAM_LOW < SOC_EXTRAM_HIGH, "Invalid I/D_EXTRAM region");
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
|
||||
const uint32_t pmpaddr12 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(12, pmpaddr12, PMP_NAPOT | CONDITIONAL_RX);
|
||||
|
||||
const uint32_t pmpaddr13 = PMPADDR_NAPOT(CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_LOW), CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_HIGH));
|
||||
PMP_RESET_AND_ENTRY_SET(13, pmpaddr13, PMP_NAPOT | CONDITIONAL_RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 8. Peripheral addresses
|
||||
const uint32_t pmpaddr27 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(27, pmpaddr27, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
|
||||
// 9. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
|
||||
// ESP32-P4 V3's 28th PMP entry cannot be used as a TOR entry // DIG-752
|
||||
PMP_RESET_AND_ENTRY_SET(28, SOC_RTC_IRAM_LOW, NONE);
|
||||
// First part of LP mem is reserved for RTC reserved mem (shared between bootloader and app)
|
||||
// as well as memory for ULP coprocessor
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_RESET_AND_ENTRY_SET(29, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_RESET_AND_ENTRY_SET(29, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
PMP_RESET_AND_ENTRY_SET(30, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(31, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr28 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(28, pmpaddr28, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void esp_cpu_configure_region_protection_rev_less_than_v3(void)
|
||||
{
|
||||
const unsigned NONE = PMP_L;
|
||||
__attribute__((unused)) const unsigned R = PMP_L | PMP_R;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
@@ -262,3 +355,71 @@ void esp_cpu_configure_region_protection(void)
|
||||
PMP_ENTRY_SET(15, pmpaddr15, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
#endif
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
*
|
||||
* 1) Note: ESP32-P4 CPU support overlapping PMP regions, configuration is based on static priority
|
||||
* feature (lowest numbered entry has highest priority).
|
||||
*
|
||||
* 2) ESP32-P4 supports 16 PMA regions so we use this feature to block the invalid address ranges.
|
||||
* However the entries are not sufficient to block all reserved memory ranges and the excluded sections are:
|
||||
* a. Region between LP ROM and LP SRAM
|
||||
* b. Region between LP peripherals and External flash (direct access)
|
||||
* c. Region between External flash (direct access) and External RAM (direct access)
|
||||
* d. Region between External RAM (direct access) and HP ROM (direct access)
|
||||
* e. Region between HP ROM (direct access) and HP L2MEM (direct access)
|
||||
*
|
||||
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
|
||||
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
|
||||
* which can be used to provide more granular access
|
||||
*
|
||||
* 4) Entries are grouped in order with some static asserts to try and verify everything is
|
||||
* correct.
|
||||
*
|
||||
* 5) For ESP32-P4's versions less than v3, no explicit permissions are specified in PMP (default all permissions) for following regions:
|
||||
* limited entries:
|
||||
* a. External RAM
|
||||
* b. LP ROM, LP Peripherals, LP SRAM
|
||||
* c. External flash, External RAM, HP ROM, HP L2MEM (direct access)
|
||||
*/
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. Application build with CONFIG_ESP_SYSTEM_MEMPROT enabled
|
||||
* - We split the SRAM into IRAM and DRAM such that IRAM region cannot be written to
|
||||
* and DRAM region cannot be executed. We use _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. Application build with CONFIG_ESP_SYSTEM_MEMPROT disabled
|
||||
* - The IRAM-DRAM split is not enabled so we just need to ensure that access to only valid address ranges are successful
|
||||
* so for that we set PMP to cover entire valid IRAM and DRAM region.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 4. CPU is in OCD debug mode
|
||||
* - The IRAM-DRAM split is not enabled so that OpenOCD can write and execute from IRAM.
|
||||
* We set PMP to cover entire valid IRAM and DRAM region.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*/
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
esp_cpu_configure_region_protection_rev_v3();
|
||||
#else
|
||||
esp_cpu_configure_region_protection_rev_less_than_v3();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -126,19 +126,31 @@ extern "C" {
|
||||
*/
|
||||
#define PMP_ENTRY_SET(ENTRY, ADDR, CFG) do { \
|
||||
RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), (ADDR) >> (PMP_SHIFT)); \
|
||||
RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \
|
||||
PMP_ENTRY_CFG_SET(ENTRY, CFG); \
|
||||
} while(0)
|
||||
|
||||
/*Only set PMPCFG entries*/
|
||||
#define PMP_ENTRY_CFG_SET(ENTRY, CFG) do {\
|
||||
RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \
|
||||
} while(0)
|
||||
#define PMP_ENTRY_CFG_SET(ENTRY, CFG) \
|
||||
RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8)
|
||||
|
||||
/*Reset all permissions of a particular PMPCFG entry*/
|
||||
#define PMP_ENTRY_CFG_RESET(ENTRY) do {\
|
||||
RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), 0); \
|
||||
RV_CLEAR_CSR((CSR_PMPCFG0) + (ENTRY)/4, (0xFF) << (ENTRY%4)*8); \
|
||||
} while(0)
|
||||
|
||||
/*Read configuration of a particular PMPCFG entry*/
|
||||
#define PMP_ENTRY_CFG_READ(ENTRY) \
|
||||
((RV_READ_CSR((CSR_PMPCFG0) + (ENTRY)/4) >> ((ENTRY%4)*8)) & 0xFF)
|
||||
|
||||
#define PMP_ENTRY_ADDR_READ(ENTRY) \
|
||||
(RV_READ_CSR((CSR_PMPADDR0) + (ENTRY)) << (PMP_SHIFT))
|
||||
|
||||
#define PMP_RESET_AND_ENTRY_SET(ENTRY, ADDR, CFG) do {\
|
||||
PMP_ENTRY_CFG_RESET(ENTRY); \
|
||||
PMP_ENTRY_SET(ENTRY, ADDR, CFG); \
|
||||
} while(0)
|
||||
|
||||
/*Reset all permissions of a particular PMACFG entry*/
|
||||
#define PMA_ENTRY_CFG_RESET(ENTRY) do {\
|
||||
RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY) , 0); \
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -26,12 +28,25 @@ void test_iram_reg2_write_violation(void);
|
||||
|
||||
void test_iram_reg3_write_violation(void);
|
||||
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
void test_non_cache_iram_reg1_write_violation(void);
|
||||
void test_non_cache_iram_reg2_write_violation(void);
|
||||
void test_non_cache_iram_reg3_write_violation(void);
|
||||
void test_non_cache_iram_reg4_write_violation(void);
|
||||
#endif
|
||||
|
||||
void test_iram_reg4_write_violation(void);
|
||||
|
||||
void test_dram_reg1_execute_violation(void);
|
||||
|
||||
void test_dram_reg2_execute_violation(void);
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
void test_non_cache_dram_reg1_execute_violation(void);
|
||||
void test_non_cache_dram_reg2_execute_violation(void);
|
||||
#endif
|
||||
|
||||
void test_rtc_fast_reg1_execute_violation(void);
|
||||
|
||||
void test_rtc_fast_reg2_execute_violation(void);
|
||||
@@ -52,6 +67,15 @@ void test_drom_reg_write_violation(void);
|
||||
|
||||
void test_drom_reg_execute_violation(void);
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
void test_non_cache_irom_reg_write_violation(void);
|
||||
void test_non_cache_drom_reg_write_violation(void);
|
||||
void test_non_cache_drom_reg_execute_violation(void);
|
||||
|
||||
void test_non_cache_spiram_xip_irom_alignment_reg_execute_violation(void);
|
||||
void test_non_cache_spiram_xip_drom_alignment_reg_execute_violation(void);
|
||||
#endif
|
||||
|
||||
void test_invalid_memory_region_write_violation(void);
|
||||
|
||||
void test_invalid_memory_region_execute_violation(void);
|
||||
|
||||
@@ -146,6 +146,13 @@ void app_main(void)
|
||||
HANDLE_TEST(test_name, test_iram_reg2_write_violation);
|
||||
HANDLE_TEST(test_name, test_iram_reg3_write_violation);
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
HANDLE_TEST(test_name, test_non_cache_iram_reg1_write_violation);
|
||||
HANDLE_TEST(test_name, test_non_cache_iram_reg2_write_violation);
|
||||
HANDLE_TEST(test_name, test_non_cache_iram_reg3_write_violation);
|
||||
HANDLE_TEST(test_name, test_non_cache_iram_reg4_write_violation);
|
||||
#endif
|
||||
|
||||
/* TODO: IDF-6820: ESP32-S2 -> Fix incorrect panic reason: Unhandled debug exception */
|
||||
HANDLE_TEST(test_name, test_iram_reg4_write_violation);
|
||||
|
||||
@@ -154,6 +161,11 @@ void app_main(void)
|
||||
|
||||
HANDLE_TEST(test_name, test_dram_reg2_execute_violation);
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
HANDLE_TEST(test_name, test_non_cache_dram_reg1_execute_violation);
|
||||
HANDLE_TEST(test_name, test_non_cache_dram_reg2_execute_violation);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SOC_RTC_FAST_MEM_SUPPORTED
|
||||
HANDLE_TEST(test_name, test_rtc_fast_reg1_execute_violation);
|
||||
HANDLE_TEST(test_name, test_rtc_fast_reg2_execute_violation);
|
||||
@@ -178,13 +190,26 @@ void app_main(void)
|
||||
HANDLE_TEST(test_name, test_irom_reg_write_violation);
|
||||
HANDLE_TEST(test_name, test_drom_reg_write_violation);
|
||||
HANDLE_TEST(test_name, test_drom_reg_execute_violation);
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
HANDLE_TEST(test_name, test_non_cache_irom_reg_write_violation);
|
||||
HANDLE_TEST(test_name, test_non_cache_drom_reg_write_violation);
|
||||
HANDLE_TEST(test_name, test_non_cache_drom_reg_execute_violation);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
|
||||
HANDLE_TEST(test_name, test_spiram_xip_irom_alignment_reg_execute_violation);
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
HANDLE_TEST(test_name, test_non_cache_spiram_xip_irom_alignment_reg_execute_violation);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2
|
||||
HANDLE_TEST(test_name, test_spiram_xip_drom_alignment_reg_execute_violation);
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
HANDLE_TEST(test_name, test_non_cache_spiram_xip_drom_alignment_reg_execute_violation);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOC_CPU_HAS_PMA
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
#include "test_memprot.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#include "hal/cache_ll.h"
|
||||
#endif
|
||||
|
||||
#define RND_VAL (0xA5A5A5A5)
|
||||
#define SPIN_ITER (16)
|
||||
|
||||
@@ -112,6 +116,40 @@ void test_iram_reg4_write_violation(void)
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
/* IRAM: I/DCACHE boundary region */
|
||||
void test_non_cache_iram_reg1_write_violation(void)
|
||||
{
|
||||
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_iram_start) - 0x04));
|
||||
printf("IRAM: Non-cacheable Write operation | Address: %p\n", test_addr);
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
|
||||
/* IRAM: Interrupt vector table region */
|
||||
void test_non_cache_iram_reg2_write_violation(void)
|
||||
{
|
||||
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_iram_text_start) - 0x04));
|
||||
printf("IRAM: Non-cacheable Write operation | Address: %p\n", test_addr);
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
|
||||
/* IRAM: Text (and data) region */
|
||||
void test_non_cache_iram_reg3_write_violation(void)
|
||||
{
|
||||
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_iram_text_end) - 0x04));
|
||||
printf("IRAM: Non-cacheable Write operation | Address: %p\n", test_addr);
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
|
||||
/* IRAM: Through the data bus */
|
||||
void test_non_cache_iram_reg4_write_violation(void)
|
||||
{
|
||||
uint32_t *test_addr = (uint32_t *)MAP_IRAM_TO_DRAM((uint32_t)&_iram_text_end - 0x04);
|
||||
printf("IRAM: Write operation | Address: %p\n", test_addr);
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
#endif /* SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE */
|
||||
|
||||
/* ---------------------------------------------------- DRAM Violation Checks ---------------------------------------------------- */
|
||||
|
||||
static void foo_d(void)
|
||||
@@ -144,6 +182,30 @@ void test_dram_reg2_execute_violation(void)
|
||||
run_function(test_addr);
|
||||
}
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
/* DRAM: Data region (DRAM_ATTR tagged) */
|
||||
void test_non_cache_dram_reg1_execute_violation(void)
|
||||
{
|
||||
memcpy(&s_dram_buf, &foo_d, sizeof(s_dram_buf));
|
||||
void *test_addr = (void *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(&s_dram_buf));
|
||||
printf("DRAM: Non-cacheable Execute operation | Address: %p\n", &s_dram_buf);
|
||||
run_function(test_addr);
|
||||
}
|
||||
|
||||
/* DRAM: Heap region */
|
||||
void test_non_cache_dram_reg2_execute_violation(void)
|
||||
{
|
||||
uint8_t *instr = calloc(1024, sizeof(uint8_t));
|
||||
assert(instr != NULL);
|
||||
|
||||
printf("DRAM: Non-cacheable Execute operation | Address: %p\n", instr);
|
||||
|
||||
memcpy(instr, &foo_d, 1024);
|
||||
void *test_addr = (void *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(instr));
|
||||
run_function(test_addr);
|
||||
}
|
||||
#endif /* SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE */
|
||||
|
||||
/* ---------------------------------------------------- RTC Violation Checks ---------------------------------------------------- */
|
||||
|
||||
#if CONFIG_SOC_RTC_FAST_MEM_SUPPORTED
|
||||
@@ -251,6 +313,30 @@ void test_drom_reg_execute_violation(void)
|
||||
run_function(test_addr);
|
||||
}
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
void test_non_cache_irom_reg_write_violation(void)
|
||||
{
|
||||
extern int _instruction_reserved_end;
|
||||
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_instruction_reserved_end - 0x100)));
|
||||
printf("Flash (IROM): Non-cacheable Write operation | Address: %p\n", test_addr);
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
|
||||
void test_non_cache_drom_reg_write_violation(void)
|
||||
{
|
||||
uint32_t *test_addr = (uint32_t *)CACHE_LL_L2MEM_NON_CACHE_ADDR(((uint32_t)(foo_buf)));
|
||||
printf("Flash (DROM): Non-cacheable Write operation | Address: %p\n", test_addr);
|
||||
*test_addr = RND_VAL;
|
||||
}
|
||||
|
||||
void test_non_cache_drom_reg_execute_violation(void)
|
||||
{
|
||||
void *test_addr = (void *)CACHE_LL_L2MEM_NON_CACHE_ADDR((void *)foo_buf);
|
||||
printf("Flash (DROM): Non-cacheable Execute operation | Address: %p\n", test_addr);
|
||||
run_function(test_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if the memory alignment gaps added to the heap are correctly configured
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
|
||||
void test_spiram_xip_irom_alignment_reg_execute_violation(void)
|
||||
@@ -264,6 +350,20 @@ void test_spiram_xip_irom_alignment_reg_execute_violation(void)
|
||||
printf("SPIRAM (IROM): IROM alignment gap not added into heap\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
void test_non_cache_spiram_xip_irom_alignment_reg_execute_violation(void)
|
||||
{
|
||||
extern int _instruction_reserved_end;
|
||||
if (ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end)) - (uint32_t)(&_instruction_reserved_end) >= 4) {
|
||||
void *test_addr = (void *)CACHE_LL_L2MEM_NON_CACHE_ADDR(&_instruction_reserved_end + 1);
|
||||
printf("SPIRAM (IROM): Non-cacheable Execute operation | Address: %p\n", test_addr);
|
||||
run_function(test_addr);
|
||||
} else {
|
||||
printf("SPIRAM (IROM): Non-cacheable IROM alignment gap not added into heap\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED */
|
||||
#endif
|
||||
|
||||
@@ -279,6 +379,20 @@ void test_spiram_xip_drom_alignment_reg_execute_violation(void)
|
||||
printf("SPIRAM (DROM): DROM alignment gap not added into heap\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
void test_non_cache_spiram_xip_drom_alignment_reg_execute_violation(void)
|
||||
{
|
||||
extern int _rodata_reserved_end;
|
||||
if (ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end)) - (uint32_t)(&_rodata_reserved_end) >= 4) {
|
||||
void *test_addr = (void *)CACHE_LL_L2MEM_NON_CACHE_ADDR(&_rodata_reserved_end + 0x4);
|
||||
printf("SPIRAM (DROM): Non-cacheable Execute operation | Address: %p\n", test_addr);
|
||||
run_function(test_addr);
|
||||
} else {
|
||||
printf("SPIRAM (DROM): Non-cacheable DROM alignment gap not added into heap\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2 */
|
||||
|
||||
#ifdef CONFIG_SOC_CPU_HAS_PMA
|
||||
|
||||
@@ -681,6 +681,8 @@ CONFIGS_MEMPROT_IDRAM = list(
|
||||
)
|
||||
)
|
||||
|
||||
CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE = list(zip(['memprot_esp32p4'], ['esp32p4']))
|
||||
|
||||
CONFIGS_MEMPROT_DCACHE = list(zip(['memprot_esp32s2'], ['esp32s2']))
|
||||
|
||||
CONFIGS_MEMPROT_RTC_FAST_MEM = list(
|
||||
@@ -714,6 +716,8 @@ CONFIGS_MEMPROT_FLASH_IDROM = list(
|
||||
)
|
||||
)
|
||||
|
||||
CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE = list(zip(['memprot_esp32p4'], ['esp32p4']))
|
||||
|
||||
CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP = list(
|
||||
zip(
|
||||
['memprot_spiram_xip_esp32c5', 'memprot_spiram_xip_esp32c61', 'memprot_spiram_xip_esp32p4'],
|
||||
@@ -721,6 +725,14 @@ CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP = list(
|
||||
)
|
||||
)
|
||||
|
||||
CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP_L2_NON_CACHE = list(
|
||||
zip(
|
||||
['memprot_spiram_xip_esp32p4'],
|
||||
['esp32p4'],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP = list(
|
||||
zip(
|
||||
[
|
||||
@@ -733,6 +745,13 @@ CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP = list(
|
||||
)
|
||||
)
|
||||
|
||||
CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP_L2_NON_CACHE = list(
|
||||
zip(
|
||||
['memprot_spiram_xip_esp32p4'],
|
||||
['esp32p4'],
|
||||
)
|
||||
)
|
||||
|
||||
CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA = list(
|
||||
zip(
|
||||
[
|
||||
@@ -769,10 +788,7 @@ def test_dcache_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
def iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
@@ -790,10 +806,58 @@ def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> No
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
iram_reg1_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
iram_reg1_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def iram_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
dut.expect_gme('Memory protection fault')
|
||||
dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_backtrace()
|
||||
elif dut.target == 'esp32c3':
|
||||
dut.expect_gme('Memory protection fault')
|
||||
dut.expect(r' memory type: (\S+)')
|
||||
dut.expect(r' faulting address: [0-9xa-f]+')
|
||||
dut.expect(r' operation type: (\S+)')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_stack_dump()
|
||||
else:
|
||||
dut.expect_gme('Store access fault')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_stack_dump()
|
||||
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
iram_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
iram_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
@@ -820,6 +884,17 @@ def test_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> No
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
iram_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
iram_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
@@ -848,36 +923,17 @@ def test_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> No
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
dut.expect_gme('Memory protection fault')
|
||||
dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_backtrace()
|
||||
elif dut.target == 'esp32c3':
|
||||
dut.expect_gme('Memory protection fault')
|
||||
dut.expect(r' memory type: (\S+)')
|
||||
dut.expect(r' faulting address: [0-9xa-f]+')
|
||||
dut.expect(r' operation type: (\S+)')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_stack_dump()
|
||||
else:
|
||||
dut.expect_gme('Store access fault')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_stack_dump()
|
||||
|
||||
dut.expect_cpu_reset()
|
||||
iram_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
# TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.xfail(
|
||||
'config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False
|
||||
)
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
iram_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
@@ -900,7 +956,18 @@ def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) ->
|
||||
)
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dram_reg1_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
dram_reg1_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
|
||||
if dut.target == 'esp32s2':
|
||||
@@ -915,6 +982,24 @@ def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) ->
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
# TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.xfail(
|
||||
'config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False
|
||||
)
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
|
||||
def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dram_reg2_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
dram_reg2_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=['config', 'target'])
|
||||
@@ -1000,10 +1085,28 @@ def test_rtc_slow_reg2_execute_violation(dut: PanicTestDut, test_func_name: str)
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
def irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
dut.expect_gme('Store access fault')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target'])
|
||||
def test_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
irom_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
irom_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
dut.expect_gme('Store access fault')
|
||||
dut.expect_reg_dump(0)
|
||||
@@ -1014,8 +1117,19 @@ def test_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> Non
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target'])
|
||||
def test_drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
drom_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
drom_reg_write_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
dut.expect_gme('Store access fault')
|
||||
dut.expect_gme('Instruction access fault')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
@@ -1024,15 +1138,17 @@ def test_drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> Non
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target'])
|
||||
def test_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
dut.expect_gme('Instruction access fault')
|
||||
dut.expect_reg_dump(0)
|
||||
dut.expect_cpu_reset()
|
||||
drom_reg_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
|
||||
def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE, indirect=['config', 'target'])
|
||||
def test_non_cache_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
drom_reg_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
try:
|
||||
dut.expect_gme('Instruction access fault')
|
||||
@@ -1043,8 +1159,21 @@ def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
|
||||
def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
|
||||
def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
spiram_xip_irom_alignment_reg_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize(
|
||||
'config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP_L2_NON_CACHE, indirect=['config', 'target']
|
||||
)
|
||||
def test_non_cache_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
spiram_xip_irom_alignment_reg_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
def spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
try:
|
||||
if dut.target == 'esp32s3':
|
||||
@@ -1057,6 +1186,21 @@ def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test
|
||||
dut.expect_cpu_reset()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
|
||||
def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
spiram_xip_drom_alignment_reg_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize(
|
||||
'config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP_L2_NON_CACHE, indirect=['config', 'target']
|
||||
)
|
||||
def test_non_cache_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
|
||||
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
spiram_xip_drom_alignment_reg_execute_violation(dut, test_func_name)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
|
||||
@idf_parametrize('config, target', CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA, indirect=['config', 'target'])
|
||||
|
||||
@@ -6,15 +6,11 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import TextIO
|
||||
from typing import Union
|
||||
|
||||
import pexpect
|
||||
from panic_utils import attach_logger
|
||||
from panic_utils import NoGdbProcessError
|
||||
from panic_utils import attach_logger
|
||||
from panic_utils import quote_string
|
||||
from panic_utils import sha256
|
||||
from panic_utils import verify_valid_gdb_subprocess
|
||||
@@ -32,7 +28,10 @@ class PanicTestDut(IdfDut):
|
||||
COREDUMP_UART_END = r'================= CORE DUMP END ================='
|
||||
COREDUMP_CHECKSUM = r"Coredump checksum='([a-fA-F0-9]+)'"
|
||||
REBOOT = r'.*Rebooting\.\.\.'
|
||||
CPU_RESET = r'.*rst:.*(RTC_SW_CPU_RST|SW_CPU_RESET|SW_CPU|RTCWDT_RTC_RESET|LP_WDT_SYS|RTCWDT_RTC_RST|CHIP_LP_WDT_RESET|RTC_WDT_SYS)\b'
|
||||
CPU_RESET = (
|
||||
r'.*rst:.*(RTC_SW_CPU_RST|SW_CPU_RESET|SW_CPU|RTCWDT_RTC_RESET|LP_WDT_SYS|'
|
||||
r'RTCWDT_RTC_RST|CHIP_LP_WDT_RESET|RTC_WDT_SYS)\b'
|
||||
)
|
||||
|
||||
app: IdfApp
|
||||
serial: IdfSerial
|
||||
@@ -40,14 +39,14 @@ class PanicTestDut(IdfDut):
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.gdbmi: Optional[GdbController] = None
|
||||
self.gdbmi: GdbController | None = None
|
||||
# record this since pygdbmi is using logging.debug to generate some single character mess
|
||||
self.log_level = logging.getLogger().level
|
||||
# pygdbmi is using logging.debug to generate some single character mess
|
||||
if self.log_level <= logging.DEBUG:
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
self.coredump_output: Optional[TextIO] = None
|
||||
self.coredump_output: TextIO | None = None
|
||||
|
||||
def close(self) -> None:
|
||||
if self.gdbmi:
|
||||
@@ -68,6 +67,8 @@ class PanicTestDut(IdfDut):
|
||||
return self.target in ['esp32', 'esp32s3', 'esp32p4']
|
||||
|
||||
def run_test_func(self, test_func_name: str) -> None:
|
||||
if self.target == 'esp32p4' and not self.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
|
||||
self.write('\n')
|
||||
self.expect_exact('Enter test name:')
|
||||
self.write(test_func_name)
|
||||
self.expect_exact('Got test name: ' + test_func_name)
|
||||
@@ -98,13 +99,13 @@ class PanicTestDut(IdfDut):
|
||||
"""Expect method for Guru Meditation Errors"""
|
||||
self.expect_exact(f"Guru Meditation Error: Core 0 panic'ed ({reason})")
|
||||
|
||||
def expect_reg_dump(self, core: Optional[int] = None) -> None:
|
||||
def expect_reg_dump(self, core: int | None = None) -> None:
|
||||
if core is None:
|
||||
# Match any core num
|
||||
self.expect(r'Core\s+\d+\s+register dump:')
|
||||
else:
|
||||
# Match the exact core num provided
|
||||
self.expect(r'Core\s+%d\s+register dump:' % core)
|
||||
self.expect(rf'Core\s+{core}\s+register dump:')
|
||||
|
||||
def expect_cpu_reset(self) -> None:
|
||||
# no digital system reset for panic handling restarts (see IDF-7255)
|
||||
@@ -113,13 +114,11 @@ class PanicTestDut(IdfDut):
|
||||
def expect_elf_sha256(self, caption: str = 'ELF file SHA256: ') -> None:
|
||||
"""Expect method for ELF SHA256 line"""
|
||||
elf_sha256 = sha256(self.app.elf_file)
|
||||
elf_sha256_len = int(
|
||||
self.app.sdkconfig.get('CONFIG_APP_RETRIEVE_LEN_ELF_SHA', '9')
|
||||
)
|
||||
elf_sha256_len = int(self.app.sdkconfig.get('CONFIG_APP_RETRIEVE_LEN_ELF_SHA', '9'))
|
||||
self.expect_exact(caption + elf_sha256[0:elf_sha256_len])
|
||||
|
||||
def expect_coredump(self, output_file_name: str, patterns: List[Union[str, re.Pattern]]) -> None:
|
||||
with open(output_file_name, 'r') as file:
|
||||
def expect_coredump(self, output_file_name: str, patterns: list[str | re.Pattern]) -> None:
|
||||
with open(output_file_name) as file:
|
||||
coredump = file.read()
|
||||
for pattern in patterns:
|
||||
if isinstance(pattern, str):
|
||||
@@ -131,16 +130,12 @@ class PanicTestDut(IdfDut):
|
||||
else:
|
||||
raise ValueError(f'Unsupported input type: {type(pattern).__name__}')
|
||||
|
||||
def _call_espcoredump(
|
||||
self, extra_args: List[str], output_file_name: str
|
||||
) -> None:
|
||||
def _call_espcoredump(self, extra_args: list[str], output_file_name: str) -> None:
|
||||
# no "with" here, since we need the file to be open for later inspection by the test case
|
||||
if not self.coredump_output:
|
||||
self.coredump_output = open(output_file_name, 'w')
|
||||
|
||||
espcoredump_script = os.path.join(
|
||||
os.environ['IDF_PATH'], 'components', 'espcoredump', 'espcoredump.py'
|
||||
)
|
||||
espcoredump_script = os.path.join(os.environ['IDF_PATH'], 'components', 'espcoredump', 'espcoredump.py')
|
||||
espcoredump_args = [
|
||||
sys.executable,
|
||||
espcoredump_script,
|
||||
@@ -157,14 +152,16 @@ class PanicTestDut(IdfDut):
|
||||
subprocess.check_call(espcoredump_args, stdout=self.coredump_output, stderr=self.coredump_output)
|
||||
except subprocess.CalledProcessError:
|
||||
self.coredump_output.flush()
|
||||
with open(output_file_name, 'r') as file:
|
||||
with open(output_file_name) as file:
|
||||
logging.error('espcoredump failed with output: %s', file.read())
|
||||
raise
|
||||
finally:
|
||||
self.coredump_output.seek(0)
|
||||
|
||||
def process_coredump_uart(
|
||||
self, coredump_base64: Any, expected: Optional[List[Union[str, re.Pattern]]] = None,
|
||||
self,
|
||||
coredump_base64: Any,
|
||||
expected: list[str | re.Pattern] | None = None,
|
||||
) -> Any:
|
||||
with open(os.path.join(self.logdir, 'coredump_data.b64'), 'w') as coredump_file:
|
||||
logging.info('Writing UART base64 core dump to %s', coredump_file.name)
|
||||
@@ -179,13 +176,11 @@ class PanicTestDut(IdfDut):
|
||||
self.expect_coredump(output_file_name, expected)
|
||||
return coredump_elf_file
|
||||
|
||||
def process_coredump_flash(self, expected: Optional[List[Union[str, re.Pattern]]] = None) -> Any:
|
||||
def process_coredump_flash(self, expected: list[str | re.Pattern] | None = None) -> Any:
|
||||
coredump_file_name = os.path.join(self.logdir, 'coredump_data.bin')
|
||||
logging.info('Writing flash binary core dump to %s', coredump_file_name)
|
||||
output_file_name = os.path.join(self.logdir, 'coredump_flash_result.txt')
|
||||
self._call_espcoredump(
|
||||
['--core-format', 'raw', '--save-core', coredump_file_name], output_file_name
|
||||
)
|
||||
self._call_espcoredump(['--core-format', 'raw', '--save-core', coredump_file_name], output_file_name)
|
||||
if expected:
|
||||
self.expect_coredump(output_file_name, expected)
|
||||
return coredump_file_name
|
||||
@@ -210,12 +205,14 @@ class PanicTestDut(IdfDut):
|
||||
gdb_path = 'riscv32-esp-elf-gdb'
|
||||
try:
|
||||
from pygdbmi.constants import GdbTimeoutError
|
||||
|
||||
gdb_command = [gdb_path] + gdb_args
|
||||
self.gdbmi = GdbController(command=gdb_command)
|
||||
pygdbmi_logger = attach_logger()
|
||||
except ImportError:
|
||||
# fallback for pygdbmi<0.10.0.0.
|
||||
from pygdbmi.gdbcontroller import GdbTimeoutError
|
||||
|
||||
self.gdbmi = GdbController(gdb_path=gdb_path, gdb_args=gdb_args)
|
||||
pygdbmi_logger = self.gdbmi.logger
|
||||
|
||||
@@ -225,9 +222,7 @@ class PanicTestDut(IdfDut):
|
||||
while pygdbmi_logger.hasHandlers():
|
||||
pygdbmi_logger.removeHandler(pygdbmi_logger.handlers[0])
|
||||
log_handler = logging.FileHandler(pygdbmi_log_file_name)
|
||||
log_handler.setFormatter(
|
||||
logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
|
||||
)
|
||||
log_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
|
||||
logging.info(f'Saving pygdbmi logs to {pygdbmi_log_file_name}')
|
||||
pygdbmi_logger.addHandler(log_handler)
|
||||
try:
|
||||
@@ -251,27 +246,22 @@ class PanicTestDut(IdfDut):
|
||||
logging.info('GDB response: %s', resp)
|
||||
break # success
|
||||
except GdbTimeoutError:
|
||||
logging.warning(
|
||||
'GDB internal error: cannot get response from the subprocess'
|
||||
)
|
||||
logging.warning('GDB internal error: cannot get response from the subprocess')
|
||||
except NoGdbProcessError:
|
||||
logging.error('GDB internal error: process is not running')
|
||||
break # failure - TODO: create another GdbController
|
||||
except ValueError:
|
||||
logging.error(
|
||||
'GDB internal error: select() returned an unexpected file number'
|
||||
)
|
||||
logging.error('GDB internal error: select() returned an unexpected file number')
|
||||
|
||||
# Set up logging for GDB remote protocol
|
||||
gdb_remotelog_file_name = os.path.join(self.logdir, 'gdb_remote_log.txt')
|
||||
self.gdb_write('-gdb-set remotelogfile ' + gdb_remotelog_file_name)
|
||||
|
||||
# Load the ELF file
|
||||
self.gdb_write('-file-exec-and-symbols {}'.format(self.app.elf_file))
|
||||
self.gdb_write(f'-file-exec-and-symbols {self.app.elf_file}')
|
||||
|
||||
# Prepare gdb for the gdb stub
|
||||
def start_gdb_for_gdbstub(self) -> None:
|
||||
|
||||
self.run_gdb()
|
||||
|
||||
# Connect GDB to UART
|
||||
@@ -280,8 +270,9 @@ class PanicTestDut(IdfDut):
|
||||
self.gdb_write('-gdb-set serial baud 115200')
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
assert '/dev/tty.' not in self.serial.port, \
|
||||
'/dev/tty.* ports can\'t be used with GDB on macOS. Use with /dev/cu.* instead.'
|
||||
assert '/dev/tty.' not in self.serial.port, (
|
||||
"/dev/tty.* ports can't be used with GDB on macOS. Use with /dev/cu.* instead."
|
||||
)
|
||||
|
||||
# Make sure we get the 'stopped' notification
|
||||
responses = self.gdb_write('-target-select remote ' + self.serial.port)
|
||||
@@ -307,9 +298,8 @@ class PanicTestDut(IdfDut):
|
||||
|
||||
# Prepare gdb to debug coredump file
|
||||
def start_gdb_for_coredump(self, elf_file: str) -> None:
|
||||
|
||||
self.run_gdb()
|
||||
self.gdb_write('core {}'.format(elf_file))
|
||||
self.gdb_write(f'core {elf_file}')
|
||||
|
||||
def gdb_backtrace(self) -> Any:
|
||||
"""
|
||||
@@ -322,13 +312,11 @@ class PanicTestDut(IdfDut):
|
||||
return self.find_gdb_response('done', 'result', responses)['payload']['stack']
|
||||
|
||||
def gdb_data_eval_expr(self, expr: str) -> Any:
|
||||
responses = self.gdb_write('-data-evaluate-expression "%s"' % expr)
|
||||
responses = self.gdb_write(f'-data-evaluate-expression "{expr}"')
|
||||
return self.find_gdb_response('done', 'result', responses)['payload']['value']
|
||||
|
||||
@staticmethod
|
||||
def verify_gdb_backtrace(
|
||||
gdb_backtrace: List[Any], expected_functions_list: List[Any]
|
||||
) -> None:
|
||||
def verify_gdb_backtrace(gdb_backtrace: list[Any], expected_functions_list: list[Any]) -> None:
|
||||
"""
|
||||
Raises an assert if the function names listed in expected_functions_list do not match the backtrace
|
||||
given by gdb_backtrace argument. The latter is in the same format as returned by gdb_backtrace()
|
||||
@@ -341,15 +329,13 @@ class PanicTestDut(IdfDut):
|
||||
assert False, 'Got unexpected backtrace'
|
||||
|
||||
@staticmethod
|
||||
def find_gdb_response(
|
||||
message: str, response_type: str, responses: List[Any]
|
||||
) -> Any:
|
||||
def find_gdb_response(message: str, response_type: str, responses: list[Any]) -> Any:
|
||||
"""
|
||||
Helper function which extracts one response from an array of GDB responses, filtering
|
||||
by message and type. Returned message is a dictionary, refer to pygdbmi docs for the format.
|
||||
"""
|
||||
|
||||
def match_response(response: Dict[str, Any]) -> bool:
|
||||
def match_response(response: dict[str, Any]) -> bool:
|
||||
return response['message'] == message and response['type'] == response_type # type: ignore
|
||||
|
||||
filtered_responses = [r for r in responses if match_response(r)]
|
||||
|
||||
Reference in New Issue
Block a user