* memprot support for RTC_SLOW

* API upgrade
JIRA IDF-1636
This commit is contained in:
Martin Vychodil
2020-10-08 11:19:23 +08:00
committed by Angus Gratton
parent 80f993bf31
commit 497b730e8f
16 changed files with 2353 additions and 492 deletions

View File

@@ -511,7 +511,6 @@ menu "ESP32S2-specific"
config ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP config ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP
bool "Enable RTC fast memory for dynamic allocations" bool "Enable RTC fast memory for dynamic allocations"
depends on !ESP32S2_MEMPROT_FEATURE
default y default y
help help
This config option allows to add RTC fast memory region to system heap with capability This config option allows to add RTC fast memory region to system heap with capability

View File

@@ -18,15 +18,22 @@
*/ */
#pragma once #pragma once
#include "esp_attr.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef enum { typedef enum {
MEMPROT_IRAM0 = 0x00000000, MEMPROT_NONE = 0x00000000,
MEMPROT_DRAM0 = 0x00000001, MEMPROT_IRAM0_SRAM = 0x00000001, //0x40020000-0x4006FFFF, RWX
MEMPROT_UNKNOWN MEMPROT_DRAM0_SRAM = 0x00000002, //0x3FFB0000-0x3FFFFFFF, RW
MEMPROT_IRAM0_RTCFAST = 0x00000004, //0x40070000-0x40071FFF, RWX
MEMPROT_DRAM0_RTCFAST = 0x00000008, //0x3FF9E000-0x3FF9FFFF, RW
MEMPROT_PERI1_RTCSLOW = 0x00000010, //0x3F421000-0x3F423000, RW
MEMPROT_PERI2_RTCSLOW_0 = 0x00000020, //0x50001000-0x50003000, RWX
MEMPROT_PERI2_RTCSLOW_1 = 0x00000040, //0x60002000-0x60004000, RWX
MEMPROT_ALL = 0xFFFFFFFF
} mem_type_prot_t; } mem_type_prot_t;
@@ -60,22 +67,6 @@ void esp_memprot_intr_init(mem_type_prot_t mem_type);
*/ */
void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable); void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable);
/**
* @brief Detects whether any of the memory protection interrupts is active
*
* @return true/false
*/
bool esp_memprot_is_assoc_intr_any(void);
/**
* @brief Detects whether specific memory protection interrupt is active
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return true/false
*/
bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type);
/** /**
* @brief Sets a request for clearing interrupt-on flag for specified memory region (register write) * @brief Sets a request for clearing interrupt-on flag for specified memory region (register write)
* *
@@ -87,11 +78,17 @@ bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type);
void esp_memprot_clear_intr(mem_type_prot_t mem_type); void esp_memprot_clear_intr(mem_type_prot_t mem_type);
/** /**
* @brief Detects which memory protection interrupt is active, check order: IRAM0, DRAM0 * @brief Detects which memory protection interrupt is active
*
* @note Check order
* MEMPROT_IRAM0_SRAM
* MEMPROT_IRAM0_RTCFAST
* MEMPROT_DRAM0_SRAM
* MEMPROT_DRAM0_RTCFAST
* *
* @return Memory protection area type (see mem_type_prot_t enum) * @return Memory protection area type (see mem_type_prot_t enum)
*/ */
mem_type_prot_t IRAM_ATTR esp_memprot_get_intr_memtype(void); mem_type_prot_t IRAM_ATTR esp_memprot_get_active_intr_memtype(void);
/** /**
* @brief Gets interrupt status register contents for specified memory region * @brief Gets interrupt status register contents for specified memory region
@@ -151,13 +148,13 @@ void esp_memprot_set_lock(mem_type_prot_t mem_type);
bool esp_memprot_get_lock(mem_type_prot_t mem_type); bool esp_memprot_get_lock(mem_type_prot_t mem_type);
/** /**
* @brief Gets interrupt permission control register contents for required memory region * @brief Gets permission control configuration register contents for required memory region
* *
* @param mem_type Memory protection area type (see mem_type_prot_t enum) * @param mem_type Memory protection area type (see mem_type_prot_t enum)
* *
* @return Permission control register contents * @return Permission control register contents
*/ */
uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type); uint32_t esp_memprot_get_conf_reg(mem_type_prot_t mem_type);
/** /**
* @brief Gets interrupt permission settings for unified management block * @brief Gets interrupt permission settings for unified management block
@@ -321,11 +318,12 @@ void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, b
* *
* @param invoke_panic_handler map mem.prot interrupt to ETS_MEMACCESS_ERR_INUM and thus invokes panic handler when fired ('true' not suitable for testing) * @param invoke_panic_handler map mem.prot interrupt to ETS_MEMACCESS_ERR_INUM and thus invokes panic handler when fired ('true' not suitable for testing)
* @param lock_feature sets LOCK bit, see esp_memprot_set_lock() ('true' not suitable for testing) * @param lock_feature sets LOCK bit, see esp_memprot_set_lock() ('true' not suitable for testing)
* @param mem_type_mask holds a set of required memory protection types (bitmask built of mem_type_prot_t). NULL means default (MEMPROT_ALL in this version)
*/ */
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature); void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask);
/** /**
* @brief Get permission settings bits for IRAM split mgmt based on current split address * @brief Get permission settings bits for IRAM0 split mgmt. Only IRAM0 memory types allowed
* *
* @param mem_type Memory protection area type (see mem_type_prot_t enum) * @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lw Low segment Write permission flag * @param lw Low segment Write permission flag
@@ -338,7 +336,7 @@ void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature);
void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx); void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx);
/** /**
* @brief Get permission settings bits for DRAM split mgmt based on current split address * @brief Get permission settings bits for DRAM0 split mgmt. Only DRAM0 memory types allowed
* *
* @param mem_type Memory protection area type (see mem_type_prot_t enum) * @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lw Low segment Write permission flag * @param lw Low segment Write permission flag
@@ -348,6 +346,145 @@ void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bo
*/ */
void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr); void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr);
/**
* @brief Sets permissions for high and low memory segment in PERIBUS1 region
*
* Sets Read and Write permission for both low and high memory segments given by splitting address.
* Applicable only to PERIBUS1 memory types
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param split_addr Address to split the memory region to lower and higher segment
* @param lw Low segment Write permission flag
* @param lr Low segment Read permission flag
* @param hw High segment Write permission flag
* @param hr High segment Read permission flag
*/
void esp_memprot_set_prot_peri1(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr);
/**
* @brief Get permission settings bits for PERIBUS1 split mgmt. Only PERIBUS1 memory types allowed
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lw Low segment Write permission flag
* @param lr Low segment Read permission flag
* @param hw High segment Write permission flag
* @param hr High segment Read permission flag
*/
void esp_memprot_get_perm_split_bits_peri1(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr);
/**
* @brief Get permission settings bits for PERIBUS2 split mgmt. Only PERIBUS2 memory types allowed
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lw Low segment Write permission flag
* @param lr Low segment Read permission flag
* @param lx Low segment Execute permission flag
* @param hw High segment Write permission flag
* @param hr High segment Read permission flag
* @param hx High segment Execute permission flag
*/
void esp_memprot_get_perm_split_bits_peri2(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx);
/**
* @brief Sets permissions for high and low memory segment in PERIBUS2 region
*
* Sets Read Write permission for both low and high memory segments given by splitting address.
* Applicable only to PERIBUS2 memory types
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param split_addr Address to split the memory region to lower and higher segment
* @param lw Low segment Write permission flag
* @param lr Low segment Read permission flag
* @param lx Low segment Execute permission flag
* @param hw High segment Write permission flag
* @param hr High segment Read permission flag
* @param hx High segment Execute permission flag
*/
void esp_memprot_set_prot_peri2(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx);
/**
* @brief Get permissions for specified memory type. Irrelevant bits are ignored
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lw Low segment Write permission flag
* @param lr Low segment Read permission flag
* @param lx Low segment Execute permission flag
* @param hw High segment Write permission flag
* @param hr High segment Read permission flag
* @param hx High segment Execute permission flag
*/
void esp_memprot_get_permissions(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx);
/**
* @brief Get Read permission settings for low and high regions of given memory type
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lr Low segment Read permission flag
* @param hr High segment Read permission flag
*/
void esp_memprot_get_perm_read(mem_type_prot_t mem_type, bool *lr, bool *hr);
/**
* @brief Get Write permission settings for low and high regions of given memory type
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lr Low segment Write permission flag
* @param hr High segment Write permission flag
*/
void esp_memprot_get_perm_write(mem_type_prot_t mem_type, bool *lw, bool *hw);
/**
* @brief Get Execute permission settings for low and high regions of given memory type
* Applicable only to IBUS-compatible memory types
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lr Low segment Exec permission flag
* @param hr High segment Exec permission flag
*/
void esp_memprot_get_perm_exec(mem_type_prot_t mem_type, bool *lx, bool *hx);
/**
* @brief Returns the lowest address in required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*/
uint32_t esp_memprot_get_low_limit(mem_type_prot_t mem_type);
/**
* @brief Returns the highest address in required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*/
uint32_t esp_memprot_get_high_limit(mem_type_prot_t mem_type);
/**
* @brief Sets READ permission bit for required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lr Low segment Read permission flag
* @param hr High segment Read permission flag
*/
void esp_memprot_set_read_perm(mem_type_prot_t mem_type, bool lr, bool hr);
/**
* @brief Sets WRITE permission bit for required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lr Low segment Write permission flag
* @param hr High segment Write permission flag
*/
void esp_memprot_set_write_perm(mem_type_prot_t mem_type, bool lw, bool hw);
/**
* @brief Sets EXECUTE permission bit for required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param lr Low segment Exec permission flag
* @param hr High segment Exec permission flag
*/
void esp_memprot_set_exec_perm(mem_type_prot_t mem_type, bool lx, bool hx);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -8,11 +8,19 @@ SECTIONS
*/ */
.rtc.text : .rtc.text :
{ {
_rtc_text_start = ABSOLUTE(.);
. = ALIGN(4); . = ALIGN(4);
_rtc_code_start = .;
mapping[rtc_text] mapping[rtc_text]
*rtc_wake_stub*.*(.literal .text .literal.* .text.*) *rtc_wake_stub*.*(.literal .text .literal.* .text.*)
_rtc_code_end = .;
/* possibly align + add 16B for CPU dummy speculative instr. fetch */
. = ((_rtc_code_end - _rtc_code_start) == 0) ? ALIGN(0) : ALIGN(4) + 16;
_rtc_text_end = ABSOLUTE(.); _rtc_text_end = ABSOLUTE(.);
} > rtc_iram_seg } > rtc_iram_seg
@@ -176,7 +184,7 @@ SECTIONS
_coredump_iram_start = 0; _coredump_iram_start = 0;
_coredump_iram_end = 0; _coredump_iram_end = 0;
/* align + add 16B for the possibly overlapping instructions */ /* align + add 16B for CPU dummy speculative instr. fetch */
. = ALIGN(4) + 16; . = ALIGN(4) + 16;
_iram_text_end = ABSOLUTE(.); _iram_text_end = ABSOLUTE(.);
_iram_end = ABSOLUTE(.); _iram_end = ABSOLUTE(.);

File diff suppressed because it is too large Load Diff

View File

@@ -186,7 +186,7 @@ void esp_panic_handler(panic_info_t *info)
info->exception = PANIC_EXCEPTION_ABORT; info->exception = PANIC_EXCEPTION_ABORT;
} }
/* /*
* For any supported chip, the panic handler prints the contents of panic_info_t in the following format: * For any supported chip, the panic handler prints the contents of panic_info_t in the following format:
* *
* *
@@ -343,6 +343,7 @@ void esp_panic_handler(panic_info_t *info)
#endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */ #endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */
} }
void __attribute__((noreturn)) panic_abort(const char *details) void __attribute__((noreturn)) panic_abort(const char *details)
{ {
g_panic_abort = true; g_panic_abort = true;

View File

@@ -433,9 +433,9 @@ void IRAM_ATTR call_start_cpu0(void)
#if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_ESP32S2_MEMPROT_FEATURE #if CONFIG_ESP32S2_MEMPROT_FEATURE
#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK #if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK
esp_memprot_set_prot(true, true); esp_memprot_set_prot(true, true, NULL);
#else #else
esp_memprot_set_prot(true, false); esp_memprot_set_prot(true, false, NULL);
#endif #endif
#endif #endif
#endif #endif

View File

@@ -371,12 +371,12 @@ static inline void print_memprot_err_details(const void *f)
{ {
uint32_t *fault_addr; uint32_t *fault_addr;
uint32_t op_type, op_subtype; uint32_t op_type, op_subtype;
mem_type_prot_t mem_type = esp_memprot_get_intr_memtype(); mem_type_prot_t mem_type = esp_memprot_get_active_intr_memtype();
esp_memprot_get_fault_status( mem_type, &fault_addr, &op_type, &op_subtype ); esp_memprot_get_fault_status( mem_type, &fault_addr, &op_type, &op_subtype );
char *operation_type = "Write"; char *operation_type = "Write";
if ( op_type == 0 ) { if ( op_type == 0 ) {
operation_type = (mem_type == MEMPROT_IRAM0 && op_subtype == 0) ? "Instruction fetch" : "Read"; operation_type = (mem_type == MEMPROT_IRAM0_SRAM && op_subtype == 0) ? "Instruction fetch" : "Read";
} }
panic_print_str( operation_type ); panic_print_str( operation_type );
@@ -506,7 +506,7 @@ static void frame_to_panic_info(XtExcFrame *frame, panic_info_t *info, bool pseu
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
if (frame->exccause == PANIC_RSN_CACHEERR) { if (frame->exccause == PANIC_RSN_CACHEERR) {
if ( esp_memprot_is_assoc_intr_any() ) { if ( esp_memprot_get_active_intr_memtype() != MEMPROT_NONE ) {
info->details = print_memprot_err_details; info->details = print_memprot_err_details;
info->reason = "Memory protection fault"; info->reason = "Memory protection fault";
} else { } else {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,453 @@
// Copyright 2020 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define RTCSLOW_MEMORY_SIZE 0x00002000
/**
* ========================================================================================
* === PeriBus1 common
* ========================================================================================
*/
//PeriBus1 interrupt status bitmasks
#define PERI1_INTR_ST_OP_TYPE_BIT BIT(4) //0: non-atomic, 1: atomic
#define PERI1_INTR_ST_OP_HIGH_BITS BIT(5) //0: high bits = unchanged, 1: high bits = 0x03F40000
#define PERI1_INTR_ST_FAULTADDR_M 0x03FFFFC0 //(bits 25:6 in the reg)
#define PERI1_INTR_ST_FAULTADDR_S 0x4 //(bits 21:2 of real address)
static inline void esp_memprot_peri1_clear_intr(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_CLR);
}
static inline uint32_t esp_memprot_peri1_get_intr_source_num(void)
{
return ETS_PMS_PRO_DPORT_ILG_INTR_SOURCE;
}
static inline void esp_memprot_peri1_intr_ena(bool enable)
{
if (enable) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN);
}
}
static inline uint32_t esp_memprot_peri1_get_ctrl_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_6_REG);
}
static inline uint32_t esp_memprot_peri1_get_fault_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_7_REG);
}
static inline void esp_memprot_peri1_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype)
{
uint32_t status_bits = esp_memprot_peri1_get_fault_reg();
//*op_type = (uint32_t)status_bits & PERI1_INTR_ST_OP_RW_BIT;
*op_type = 0;
//! DPORT_PMS_PRO_DPORT_7_REG is missing op_type bit
*op_subtype = (uint32_t)status_bits & PERI1_INTR_ST_OP_TYPE_BIT;
}
static inline bool esp_memprot_peri1_is_assoc_intr(void)
{
return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_7_REG, DPORT_PMS_PRO_DPORT_ILG_INTR) > 0;
}
static inline uint32_t esp_memprot_peri1_get_intr_ena_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN);
}
static inline uint32_t esp_memprot_peri1_get_intr_on_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_INTR);
}
static inline uint32_t esp_memprot_peri1_get_intr_clr_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_CLR);
}
static inline uint32_t esp_memprot_peri1_get_lock_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_0_REG);
}
//resets automatically on CPU restart
static inline void esp_memprot_peri1_set_lock(void)
{
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DPORT_0_REG, DPORT_PMS_PRO_DPORT_LOCK);
}
static inline uint32_t esp_memprot_peri1_get_lock_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_0_REG, DPORT_PMS_PRO_DPORT_LOCK);
}
/**
* ========================================================================================
* === PeriBus1 RTC SLOW
* ========================================================================================
*/
#define PERI1_RTCSLOW_ADDRESS_BASE 0x3F421000
#define PERI1_RTCSLOW_ADDRESS_LOW PERI1_RTCSLOW_ADDRESS_BASE
#define PERI1_RTCSLOW_ADDRESS_HIGH PERI1_RTCSLOW_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE
#define PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 0x3F400000
static inline uint32_t *esp_memprot_peri1_rtcslow_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_peri1_get_fault_reg();
uint32_t fault_address = (status_bits & PERI1_INTR_ST_FAULTADDR_M) >> PERI1_INTR_ST_FAULTADDR_S;
uint32_t high_bits = (status_bits & PERI1_INTR_ST_OP_HIGH_BITS) ? PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 : 0;
return (uint32_t *)(fault_address | high_bits);
}
static inline bool esp_memprot_peri1_rtcslow_is_intr_mine(void)
{
if (esp_memprot_dram0_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_peri1_rtcslow_get_fault_address();
return (uint32_t)faulting_address >= PERI1_RTCSLOW_ADDRESS_LOW && (uint32_t)faulting_address <= PERI1_RTCSLOW_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_peri1_rtcslow_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
{
uint32_t addr = (uint32_t)split_addr;
//check split address is WORD aligned
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_DPORT_RTCSLOW_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_L_R;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_H_R;
}
//write PERIBUS1 RTC SLOW cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_peri1_rtcslow_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_R);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_R);
}
static inline void esp_memprot_peri1_rtcslow_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_peri1_rtcslow_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_W, hw ? 1 : 0);
}
static inline uint32_t esp_memprot_peri1_rtcslow_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG);
}
/**
* ========================================================================================
* === PeriBus2 common
* ========================================================================================
*/
//PeriBus2 interrupt status bitmasks
#define PERI2_INTR_ST_OP_TYPE_BIT BIT(1) //instruction: 0, data: 1
#define PERI2_INTR_ST_OP_RW_BIT BIT(0) //read: 0, write: 1
#define PERI2_INTR_ST_FAULTADDR_M 0xFFFFFFFC //(bits 31:2 in the reg)
static inline void esp_memprot_peri2_clear_intr(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_CLR);
}
static inline uint32_t esp_memprot_peri2_get_intr_source_num(void)
{
return ETS_PMS_PRO_AHB_ILG_INTR_SOURCE;
}
static inline void esp_memprot_peri2_intr_ena(bool enable)
{
if (enable) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN);
}
}
static inline uint32_t esp_memprot_peri2_get_ctrl_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_3_REG);
}
static inline uint32_t esp_memprot_peri2_get_fault_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_4_REG);
}
static inline void esp_memprot_peri2_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype)
{
uint32_t status_bits = esp_memprot_peri2_get_fault_reg();
*op_type = (uint32_t)status_bits & PERI2_INTR_ST_OP_RW_BIT;
*op_subtype = (uint32_t)status_bits & PERI2_INTR_ST_OP_TYPE_BIT;
}
static inline bool esp_memprot_peri2_is_assoc_intr(void)
{
return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_INTR) > 0;
}
static inline uint32_t esp_memprot_peri2_get_intr_ena_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN);
}
static inline uint32_t esp_memprot_peri2_get_intr_on_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_INTR);
}
static inline uint32_t esp_memprot_peri2_get_intr_clr_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_CLR);
}
static inline uint32_t esp_memprot_peri2_get_lock_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_0_REG);
}
//resets automatically on CPU restart
static inline void esp_memprot_peri2_set_lock(void)
{
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_0_REG, DPORT_PMS_PRO_AHB_LOCK);
}
static inline uint32_t esp_memprot_peri2_get_lock_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_0_REG, DPORT_PMS_PRO_AHB_LOCK);
}
static inline uint32_t *esp_memprot_peri2_rtcslow_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_peri2_get_fault_reg();
return (uint32_t *)(status_bits & PERI2_INTR_ST_FAULTADDR_M);
}
/**
* ========================================================================================
* === PeriBus2 RTC SLOW 0 (AHB0)
* ========================================================================================
*/
#define PERI2_RTCSLOW_0_ADDRESS_BASE 0x50000000
#define PERI2_RTCSLOW_0_ADDRESS_LOW PERI2_RTCSLOW_0_ADDRESS_BASE
#define PERI2_RTCSLOW_0_ADDRESS_HIGH PERI2_RTCSLOW_0_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE
static inline bool esp_memprot_peri2_rtcslow_0_is_intr_mine(void)
{
if (esp_memprot_peri2_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address();
return (uint32_t)faulting_address >= PERI2_RTCSLOW_0_ADDRESS_LOW && (uint32_t)faulting_address <= PERI2_RTCSLOW_0_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_peri2_rtcslow_0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
uint32_t addr = (uint32_t)split_addr;
//check split address is WORD aligned
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_AHB_RTCSLOW_0_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R;
}
if (lx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R;
}
if (hx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F;
}
//write PERIBUS1 RTC SLOW cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_1_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_peri2_rtcslow_0_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R);
*lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R);
*hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F);
}
static inline void esp_memprot_peri2_rtcslow_0_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_0_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W, hw ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_0_set_exec_perm(bool lx, bool hx)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F, lx ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F, hx ? 1 : 0);
}
static inline uint32_t esp_memprot_peri2_rtcslow_0_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG);
}
/**
* ========================================================================================
* === PeriBus2 RTC SLOW 1 (AHB1)
* ========================================================================================
*/
#define PERI2_RTCSLOW_1_ADDRESS_BASE 0x60021000
#define PERI2_RTCSLOW_1_ADDRESS_LOW PERI2_RTCSLOW_1_ADDRESS_BASE
#define PERI2_RTCSLOW_1_ADDRESS_HIGH PERI2_RTCSLOW_1_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE
static inline bool esp_memprot_peri2_rtcslow_1_is_intr_mine(void)
{
if (esp_memprot_peri2_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address();
return (uint32_t)faulting_address >= PERI2_RTCSLOW_1_ADDRESS_LOW && (uint32_t)faulting_address <= PERI2_RTCSLOW_1_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_peri2_rtcslow_1_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
uint32_t addr = (uint32_t)split_addr;
//check split address is WORD aligned
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_AHB_RTCSLOW_1_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R;
}
if (lx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R;
}
if (hx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F;
}
//write PERIBUS1 RTC SLOW cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_2_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_peri2_rtcslow_1_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R);
*lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R);
*hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F);
}
static inline void esp_memprot_peri2_rtcslow_1_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_1_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W, hw ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_1_set_exec_perm(bool lx, bool hx)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F, lx ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F, hx ? 1 : 0);
}
static inline uint32_t esp_memprot_peri2_rtcslow_1_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_2_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -415,6 +415,12 @@ test_app_test_003:
- ESP32 - ESP32
- Example_PPP - Example_PPP
test_app_test_004:
extends: .test_app_template
tags:
- ESP32S2
- Example_GENERIC
component_ut_test_001: component_ut_test_001:
extends: .component_ut_template extends: .component_ut_template
tags: tags:

View File

@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.5)
if(IDF_TARGET STREQUAL "esp32s2")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_memprot)
target_link_libraries(${project_elf} "-Wl,--wrap=esp_panic_handler")
endif()

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
import ttfw_idf
from tiny_test_fw import Utility
mem_test = [
['IRAM0_SRAM', 'WRX'],
['IRAM0_RTCFAST', 'WRX'],
['DRAM0_SRAM', 'WR'],
['DRAM0_RTCFAST', 'WR'],
['PERI1_RTCSLOW', 'WR'],
['PERI2_RTCSLOW_0', 'WRX'],
['PERI2_RTCSLOW_1', 'WRX']
]
@ttfw_idf.idf_custom_test(env_tag="Example_GENERIC", target="esp32s2", group="test-apps")
def test_memprot(env, extra_data):
dut = env.get_dut("memprot", "tools/test_apps/system/memprot")
dut.start_app()
for i in mem_test:
if 'R' in i[1]:
dut.expect(i[0] + " read low: OK")
dut.expect(i[0] + " read high: OK")
if 'W' in i[1]:
dut.expect(i[0] + " write low: OK")
dut.expect(i[0] + " write high: OK")
if 'X' in i[1]:
dut.expect(i[0] + " exec low: OK")
dut.expect(i[0] + " exec high: OK")
Utility.console_log("Memprot test done")
if __name__ == '__main__':
test_memprot()

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "test_memprot_main.c" "test_panic.c"
INCLUDE_DIRS "")

View File

@@ -0,0 +1,484 @@
/* MEMPROT IramDram testing code */
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_spi_flash.h"
#include "esp32s2/memprot.h"
#include <string.h>
#include "esp_log.h"
/*
* ESP32S2 MEMORY PROTECTION MODULE TEST
* =====================================
*
* In order to safely test all the mem_prot features, this test uses a proprietary setting
* for all splitting addresses, ie it partially overrides production settings.
* Each operation is tested at [test-splitting-addr - 16B] (low region) and
* [test-splitting-addr + 16B] (high region). Complete testing scheme
* is depicted below, the addresses used come from this application binary:
*
* ********************************************************************************************
*
* IRAM0 SRAM (320kB) DRAM0
* ===========================
* (_iram_text_end) | | (_data_start)
* 0x4002B51C(!) <-------- real splt.addr --------> 0x3FFBB520
* | |
* 0x4002DA30 <---|-------------------------|--> 0x3FFBDA30
* | test buffer (64 kB) |
* | ... |
* 0x40035A30 <-------- test splt.addr --------> 0x3FFC5A30
* | ... |
* |-------------------------|
* | |
* ===========================
*
* RTC_FAST (8kB)
* (_rtc_text_end) =========================== (_rtc_dummy_end)
* 0x40070000 <-------- real splt.addr --------> 0x3FF9E000
* | |
* | test buffer (7 kB) |
* | ... |
* 0x40070E00 <-------- test splt.addr --------> 0x3FF9EE00
* | ... |
* |-------------------------|
* | |
* ===========================
*
* ********************************************************************************************
*
* PERIBUS_1 RTC_SLOW (8/768kB) PERIBUS_2_0 PERIBUS_2_1
* ===========================
* | |
* 0x3F421000 <-------- real splt.addr --------> 0x50000000 0x60021000
* | |
* | test buffer (7 kB) |
* | ... |
* 0x3F421E00 <-------- test splt.addr --------> 0x50000E00 0x60021E00
* | ... |
* |-------------------------|
* | |
* ===========================
*
* ********************************************************************************************
*/
/* !!!IMPORTANT!!!
* a0 needs to be saved/restored manually (not clobbered) to avoid return address corruption
* caused by ASM block handling
*/
#define CODE_EXEC(code_buf, param, res) \
asm volatile ( \
"mov a3, a0\n\t" \
"movi a2," #param "\n\t" \
"callx0 %1\n\t" \
"mov %0,a2\n\t" \
"mov a0, a3\n\t" \
: "=r"(res) \
: "r"(code_buf) \
: "a2", "a3" );
/* Binary code for the following asm:
*
.type _testfunc,@function
.global _testfunc
.align 4
_testfunc:
slli a2, a2, 1
ret.n
*/
static uint8_t fnc_call0_buff[] = {0xf0, 0x22, 0x11, 0x0d, 0xf0, 0x00, 0x00, 0x00};
#define SRAM_DUMMY_BUFFER_SIZE 64*1024
#define RTCFAST_DUMMY_BUFFER_SIZE 7*1024
#define RTCSLOW_DUMMY_BUFFER_SIZE 7*1024
volatile bool g_override_illegal_instruction = false;
static uint8_t sram_dummy_buffer[SRAM_DUMMY_BUFFER_SIZE] = {0};
static uint8_t RTC_FAST_ATTR rtcfast_dummy_buffer[RTCFAST_DUMMY_BUFFER_SIZE] = {0};
static uint8_t RTC_SLOW_ATTR rtcslow_dummy_buffer[RTCSLOW_DUMMY_BUFFER_SIZE] = {0};
/* ********************************************************************************************
* testing regions and splitting address scheme
*
*/
static uint32_t *test_memprot_dram0_sram_get_min_split_addr(void)
{
return (uint32_t *)(sram_dummy_buffer + sizeof(sram_dummy_buffer) / 2);
}
static uint32_t *test_memprot_dram0_rtcfast_get_min_split_addr(void)
{
return (uint32_t *)(rtcfast_dummy_buffer + sizeof(rtcfast_dummy_buffer) / 2);
}
static uint32_t *test_memprot_iram0_sram_get_min_split_addr(void)
{
return (uint32_t *)
((uint32_t)test_memprot_dram0_sram_get_min_split_addr() +
+ esp_memprot_get_low_limit(MEMPROT_IRAM0_SRAM)
- esp_memprot_get_low_limit(MEMPROT_DRAM0_SRAM));
}
static uint32_t *test_memprot_iram0_rtcfast_get_min_split_addr(void)
{
return (uint32_t *)
((uint32_t)test_memprot_dram0_rtcfast_get_min_split_addr()
+ esp_memprot_get_low_limit(MEMPROT_IRAM0_RTCFAST)
- esp_memprot_get_low_limit(MEMPROT_DRAM0_RTCFAST));
}
static uint32_t *test_memprot_peri2_rtcslow_0_get_min_split_addr(void)
{
return (uint32_t *)(rtcslow_dummy_buffer + sizeof(rtcslow_dummy_buffer) / 2);
}
static uint32_t *test_memprot_peri1_rtcslow_get_min_split_addr(void)
{
return (uint32_t *)
((uint32_t)test_memprot_peri2_rtcslow_0_get_min_split_addr()
- (esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_0)
- esp_memprot_get_low_limit(MEMPROT_PERI1_RTCSLOW)));
}
static uint32_t *test_memprot_peri2_rtcslow_1_get_min_split_addr(void)
{
return (uint32_t *)
((uint32_t)test_memprot_peri2_rtcslow_0_get_min_split_addr()
+ esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_1)
- esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_0));
}
static uint32_t *test_memprot_get_split_addr(mem_type_prot_t mem_type)
{
switch (mem_type) {
case MEMPROT_IRAM0_SRAM:
return test_memprot_iram0_sram_get_min_split_addr();
case MEMPROT_DRAM0_SRAM:
return test_memprot_dram0_sram_get_min_split_addr();
case MEMPROT_IRAM0_RTCFAST:
return test_memprot_iram0_rtcfast_get_min_split_addr();
case MEMPROT_DRAM0_RTCFAST:
return test_memprot_dram0_rtcfast_get_min_split_addr();
case MEMPROT_PERI1_RTCSLOW:
return test_memprot_peri1_rtcslow_get_min_split_addr();
case MEMPROT_PERI2_RTCSLOW_0:
return test_memprot_peri2_rtcslow_0_get_min_split_addr();
case MEMPROT_PERI2_RTCSLOW_1:
return test_memprot_peri2_rtcslow_1_get_min_split_addr();
default:
abort();
}
}
/*
* testing setup of the memory-protection module
*/
static void test_memprot_set_prot(uint32_t *mem_type_mask, bool use_panic_handler)
{
//any IRAM0/DRAM0 enable/disable call applies to all memory modules connected
uint32_t required_mem_prot = mem_type_mask == NULL ? (uint32_t)MEMPROT_ALL : *mem_type_mask;
bool use_iram0 = required_mem_prot & MEMPROT_IRAM0_SRAM || required_mem_prot & MEMPROT_IRAM0_RTCFAST;
bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM || required_mem_prot & MEMPROT_DRAM0_RTCFAST;
bool use_peri1 = required_mem_prot & MEMPROT_PERI1_RTCSLOW;
bool use_peri2 = required_mem_prot & MEMPROT_PERI2_RTCSLOW_0 || required_mem_prot & MEMPROT_PERI2_RTCSLOW_1;
//disable protection
if (use_iram0) {
esp_memprot_intr_ena(MEMPROT_IRAM0_SRAM, false);
}
if (use_dram0) {
esp_memprot_intr_ena(MEMPROT_DRAM0_SRAM, false);
}
if (use_peri1) {
esp_memprot_intr_ena(MEMPROT_PERI1_RTCSLOW, false);
}
if (use_peri2) {
esp_memprot_intr_ena(MEMPROT_PERI2_RTCSLOW_0, false);
}
if ( use_panic_handler ) {
if (use_iram0) {
esp_memprot_intr_init(MEMPROT_IRAM0_SRAM);
}
if (use_dram0) {
esp_memprot_intr_init(MEMPROT_DRAM0_SRAM);
}
if (use_peri1) {
esp_memprot_intr_init(MEMPROT_PERI1_RTCSLOW);
}
if (use_peri2) {
esp_memprot_intr_init(MEMPROT_PERI2_RTCSLOW_0);
}
}
//set permissions
if (required_mem_prot & MEMPROT_IRAM0_SRAM) {
esp_memprot_set_prot_iram(MEMPROT_IRAM0_SRAM, test_memprot_iram0_sram_get_min_split_addr(), true, true, true, true, true, false);
}
if (required_mem_prot & MEMPROT_IRAM0_RTCFAST) {
esp_memprot_set_prot_iram(MEMPROT_IRAM0_RTCFAST, test_memprot_iram0_rtcfast_get_min_split_addr(), false, true, true, true, true, false);
}
if (required_mem_prot & MEMPROT_DRAM0_SRAM) {
esp_memprot_set_prot_dram(MEMPROT_DRAM0_SRAM, test_memprot_dram0_sram_get_min_split_addr(), true, true, true, true);
}
if (required_mem_prot & MEMPROT_DRAM0_RTCFAST) {
esp_memprot_set_prot_dram(MEMPROT_DRAM0_RTCFAST, test_memprot_dram0_rtcfast_get_min_split_addr(), false, true, true, true);
}
if (required_mem_prot & MEMPROT_PERI1_RTCSLOW) {
esp_memprot_set_prot_peri1(MEMPROT_PERI1_RTCSLOW, test_memprot_peri1_rtcslow_get_min_split_addr(), true, true, true, true);
}
if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_0) {
esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_0, test_memprot_peri2_rtcslow_0_get_min_split_addr(), true, true, false, true, true, false);
}
if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_1) {
esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_1, test_memprot_peri2_rtcslow_1_get_min_split_addr(), true, true, false, true, true, false);
}
//reenable protection (bus based)
if (use_iram0) {
esp_memprot_intr_ena(MEMPROT_IRAM0_SRAM, true);
}
if (use_dram0) {
esp_memprot_intr_ena(MEMPROT_DRAM0_SRAM, true);
}
if (use_peri1) {
esp_memprot_intr_ena(MEMPROT_PERI1_RTCSLOW, true);
}
if (use_peri2) {
esp_memprot_intr_ena(MEMPROT_PERI2_RTCSLOW_0, true);
}
}
/* ********************************************************************************************
* auxiliary functions
*/
static void __attribute__((unused)) dump_fnc_buff(uint32_t *buff)
{
esp_rom_printf( "0x%08X: 0x%08X-0x%08X\n", (uint32_t)buff, buff[0], buff[1] );
}
static void __attribute__((unused)) dump_bus_permissions(mem_type_prot_t mem_type)
{
bool write_perm_low, write_perm_high, read_perm_low, read_perm_high, exec_perm_low, exec_perm_high;
esp_memprot_get_permissions(mem_type, &write_perm_low, &write_perm_high, &read_perm_low, &read_perm_high, &exec_perm_low, &exec_perm_high);
esp_rom_printf("%s permissions: LW=%u LR=%u LX=%u HW=%u HR=%u HX=%u\n", esp_memprot_type_to_str(mem_type),
write_perm_low, read_perm_low, exec_perm_low, write_perm_high, read_perm_high, exec_perm_high);
}
static void __attribute__((unused)) dump_status_register(mem_type_prot_t mem_type)
{
uint32_t *faulting_address, op_type, op_subtype;
esp_memprot_get_fault_status(mem_type, &faulting_address, &op_type, &op_subtype);
esp_rom_printf(
" FAULT [split addr: 0x%08X, fault addr: 0x%08X, fault status: 0x%08X]\n",
(uint32_t)test_memprot_get_split_addr(mem_type),
(uint32_t)faulting_address,
esp_memprot_get_fault_reg(mem_type)
);
}
/* ********************************************************************************************
* testing functions
*/
static void check_test_result(mem_type_prot_t mem_type, bool expected_status)
{
uint32_t fault = esp_memprot_get_fault_reg(mem_type);
bool test_result = expected_status ? fault == 0 : fault != 0;
if ( test_result ) {
esp_rom_printf("OK\n");
} else {
dump_status_register(mem_type);
}
}
static void test_memprot_read(mem_type_prot_t mem_type)
{
//get current READ & WRITE permission settings
bool write_perm_low, write_perm_high, read_perm_low, read_perm_high;
esp_memprot_get_perm_read(mem_type, &write_perm_low, &write_perm_high);
esp_memprot_get_perm_read(mem_type, &read_perm_low, &read_perm_high);
//get current splitting address
volatile uint32_t *ptr = test_memprot_get_split_addr(mem_type);
//temporarily allow WRITE for setting the test values
const uint32_t test_val = 100;
esp_memprot_set_write_perm(mem_type, true, true);
*(ptr - 4) = test_val;
*(ptr + 4) = test_val + 1;
esp_memprot_set_write_perm(mem_type, write_perm_low, write_perm_high);
//perform READ in low region
esp_rom_printf("%s read low: ", esp_memprot_type_to_str(mem_type));
esp_memprot_clear_intr(mem_type);
volatile uint32_t val = *(ptr - 4);
if ( val != 0 && val != test_val ) {
esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val );
dump_status_register(mem_type);
} else {
check_test_result(mem_type, val == test_val);
}
//perform read in high region
esp_rom_printf("%s read high: ", esp_memprot_type_to_str(mem_type));
esp_memprot_clear_intr(mem_type);
val = *(ptr + 4);
if ( val != 0 && val != (test_val + 1) ) {
esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val);
dump_status_register(mem_type);
} else {
check_test_result(mem_type, val == (test_val + 1));
}
}
static void test_memprot_write(mem_type_prot_t mem_type)
{
//get current READ & WRITE permission settings
bool write_perm_low, write_perm_high, read_perm_low, read_perm_high;
esp_memprot_get_perm_read(mem_type, &write_perm_low, &write_perm_high);
esp_memprot_get_perm_read(mem_type, &read_perm_low, &read_perm_high);
//temporarily allow READ operation
esp_memprot_set_read_perm(mem_type, true, true);
//get current splitting address
volatile uint32_t *ptr = test_memprot_get_split_addr(mem_type);
//perform WRITE in low region
const uint32_t test_val = 10;
esp_rom_printf("%s write low: ", esp_memprot_type_to_str(mem_type));
esp_memprot_clear_intr(mem_type);
volatile uint32_t val = 0;
*(ptr - 4) = test_val;
val = *(ptr - 4);
if ( val != test_val && write_perm_low ) {
esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val);
dump_status_register(mem_type);
} else {
check_test_result(mem_type, write_perm_low);
}
//perform WRITE in high region
esp_rom_printf("%s write high: ", esp_memprot_type_to_str(mem_type));
esp_memprot_clear_intr(mem_type);
val = 0;
*(ptr + 4) = test_val + 1;
val = *(ptr + 4);
if ( val != (test_val + 1) && write_perm_high ) {
esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val);
dump_status_register(mem_type);
} else {
check_test_result(mem_type, write_perm_high);
}
}
static void test_memprot_exec(mem_type_prot_t mem_type)
{
//store current write permissions
bool write_perm_low, write_perm_high;
esp_memprot_get_perm_write(mem_type, &write_perm_low, &write_perm_high);
//get current EXEC permission settings
bool exec_perm_low, exec_perm_high;
esp_memprot_get_perm_exec(mem_type, &exec_perm_low, &exec_perm_high);
volatile uint32_t *fnc_ptr_low = (uint32_t *)(test_memprot_get_split_addr(mem_type) - 4);
volatile uint32_t *fnc_ptr_high = (uint32_t *)(test_memprot_get_split_addr(mem_type) + 4);
//enable WRITE permission for both segments
esp_memprot_set_write_perm(mem_type, true, true);
//inject the code to both low & high segments
memcpy( (void *)fnc_ptr_low, fnc_call0_buff, sizeof(fnc_call0_buff) );
memcpy( (void *)fnc_ptr_high, fnc_call0_buff, sizeof(fnc_call0_buff) );
//restore original WRITE perms
esp_memprot_set_write_perm(mem_type, write_perm_low, write_perm_high);
uint32_t res = 0;
//LOW REGION: clear the intr flag & try to execute the code injected
esp_memprot_clear_intr(mem_type);
esp_rom_printf("%s exec low: ", esp_memprot_type_to_str(mem_type));
g_override_illegal_instruction = true;
CODE_EXEC(fnc_ptr_low, 5, res);
g_override_illegal_instruction = false;
//check results
bool fnc_call_ok = res == 10;
if ( fnc_call_ok ) {
check_test_result(mem_type, exec_perm_low);
} else {
if ( !exec_perm_low ) {
check_test_result(mem_type, true);
} else {
esp_rom_printf(" FAULT [injected code not executed]\n");
}
}
//HIGH REGION: clear the intr flag & try to execute the code injected
esp_memprot_clear_intr(mem_type);
esp_rom_printf("%s exec high: ", esp_memprot_type_to_str(mem_type));
g_override_illegal_instruction = true;
CODE_EXEC(fnc_ptr_high, 6, res);
g_override_illegal_instruction = false;
fnc_call_ok = res == 12;
if ( fnc_call_ok ) {
check_test_result(mem_type, exec_perm_high);
} else {
if ( !exec_perm_high ) {
check_test_result(mem_type, true);
} else {
esp_rom_printf(" FAULT [injected code not executed]\n");
}
}
}
/* ********************************************************************************************
* main test runner
*/
void app_main(void)
{
test_memprot_set_prot(NULL, false);
test_memprot_read(MEMPROT_IRAM0_SRAM);
test_memprot_write(MEMPROT_IRAM0_SRAM);
test_memprot_exec(MEMPROT_IRAM0_SRAM);
test_memprot_read(MEMPROT_IRAM0_RTCFAST);
test_memprot_write(MEMPROT_IRAM0_RTCFAST);
test_memprot_exec(MEMPROT_IRAM0_RTCFAST);
test_memprot_read(MEMPROT_DRAM0_SRAM);
test_memprot_write(MEMPROT_DRAM0_SRAM);
test_memprot_read(MEMPROT_DRAM0_RTCFAST);
test_memprot_write(MEMPROT_DRAM0_RTCFAST);
test_memprot_read(MEMPROT_PERI1_RTCSLOW);
test_memprot_write(MEMPROT_PERI1_RTCSLOW);
test_memprot_read(MEMPROT_PERI2_RTCSLOW_0);
test_memprot_write(MEMPROT_PERI2_RTCSLOW_0);
test_memprot_exec(MEMPROT_PERI2_RTCSLOW_0);
test_memprot_read(MEMPROT_PERI2_RTCSLOW_1);
test_memprot_write(MEMPROT_PERI2_RTCSLOW_1);
test_memprot_exec(MEMPROT_PERI2_RTCSLOW_1);
}

View File

@@ -0,0 +1,44 @@
// 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 "freertos/xtensa_context.h"
#include "esp_private/panic_internal.h"
extern void esp_panic_handler(panic_info_t *info);
extern volatile bool g_override_illegal_instruction;
void __real_esp_panic_handler(panic_info_t *info);
/* Memprot test specific IllegalInstruction exception handler:
* when testing the protection against a code execution, sample code
* is being injected into various memory regions which produces
* EXCCAUSE_ILLEGAL on execution attempt. Such a result is expected
* but it causes system reboot in the standard panic handler.
* The following variant of panic handling simply returns back to the
* next instruction and continues normal execution.
*
* NOTE: if EXCCAUSE_ILLEGAL comes from a different source than the testing code
* the behavior is undefined
* */
void __wrap_esp_panic_handler(panic_info_t *info)
{
XtExcFrame *frm = (XtExcFrame *)info->frame;
if ( frm->exccause == EXCCAUSE_ILLEGAL && g_override_illegal_instruction == true ) {
frm->pc = frm->a0;
return;
} else {
__real_esp_panic_handler(info);
}
}

View File

@@ -0,0 +1,5 @@
# Esp32S2 only
CONFIG_IDF_TARGET="esp32s2"
# Disable automatic memory protection
CONFIG_ESP32S2_MEMPROT_FEATURE=n