esp32s2: IRAM/DRAM memory protection

* new mem_prot API
* mem_prot on & locked by default (see Kconfig)
* feature activated in start_cpu0_default()

JIRA IDF-1355
This commit is contained in:
Martin Vychodil
2020-03-10 16:46:10 +01:00
parent 412c43d9b9
commit 7491ea677a
22 changed files with 1699 additions and 91 deletions

View File

@@ -12,6 +12,7 @@ else()
# Regular app build
set(srcs "cache_err_int.c"
"memprot.c"
"clk.c"
"cpu_start.c"
"crosscore_int.c"

View File

@@ -29,6 +29,29 @@ menu "ESP32S2-specific"
default 160 if ESP32S2_DEFAULT_CPU_FREQ_160
default 240 if ESP32S2_DEFAULT_CPU_FREQ_240
menu "Memory protection"
config ESP32S2_MEMPROT_FEATURE
bool "Enable memory protection"
default "y"
help
If enabled, permission control module watches all memory access and fires panic handler
if permission violation is detected. This feature automatically splits
memory into data and instruction segments and sets Read/Execute permissions
for instruction part (below splitting address) and Read/Write permissions
for data part (above splitting address). The memory protection is effective
on all access through IRAM0 and DRAM0 buses.
config ESP32S2_MEMPROT_FEATURE_LOCK
depends on ESP32S2_MEMPROT_FEATURE
bool "Lock memory protection settings"
default "y"
help
Once locked, memory protection settings cannot be changed anymore.
The lock is reset only on the chip startup.
endmenu # Memory protection
menu "Cache config"
choice ESP32S2_INSTRUCTION_CACHE_SIZE

View File

@@ -36,13 +36,13 @@
void esp_cache_err_int_init(void)
{
uint32_t core_id = xPortGetCoreID();
ESP_INTR_DISABLE(ETS_CACHEERR_INUM);
ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM);
// We do not register a handler for the interrupt because it is interrupt
// level 4 which is not serviceable from C. Instead, xtensa_vectors.S has
// a call to the panic handler for
// this interrupt.
intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_CACHEERR_INUM);
intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_MEMACCESS_ERR_INUM);
// Enable invalid cache access interrupt when the cache is disabled.
// When the interrupt happens, we can not determine the CPU where the
@@ -73,7 +73,7 @@ void esp_cache_err_int_init(void)
EXTMEM_IC_SYNC_SIZE_FAULT_INT_ENA |
EXTMEM_CACHE_DBG_EN);
ESP_INTR_ENABLE(ETS_CACHEERR_INUM);
ESP_INTR_ENABLE(ETS_MEMACCESS_ERR_INUM);
}
int IRAM_ATTR esp_cache_err_get_cpuid(void)

View File

@@ -26,6 +26,7 @@
#include "esp32s2/brownout.h"
#include "esp32s2/cache_err_int.h"
#include "esp32s2/spiram.h"
#include "esp32s2/memprot.h"
#include "soc/cpu.h"
#include "soc/rtc.h"
@@ -317,6 +318,14 @@ void start_cpu0_default(void)
err = esp_pthread_init();
assert(err == ESP_OK && "Failed to init pthread module!");
#if CONFIG_ESP32S2_MEMPROT_FEATURE
#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK
esp_memprot_set_prot(true, true);
#else
esp_memprot_set_prot(true, false);
#endif
#endif
do_global_ctors();
#if CONFIG_ESP_INT_WDT
esp_int_wdt_init();
@@ -353,6 +362,7 @@ void start_cpu0_default(void)
ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, 0);
assert(res == pdTRUE);
ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
vTaskStartScheduler();
abort(); /* Only get to here if not enough free heap to start scheduler */

View File

@@ -20,7 +20,7 @@ extern "C" {
* @brief initialize cache invalid access interrupt
*
* This function enables cache invalid access interrupt source and connects it
* to interrupt input number ETS_CACHEERR_INUM (see soc/soc.h). It is called
* to interrupt input number ETS_MEMACCESS_ERR_INUM (see soc/soc.h). It is called
* from the startup code.
*/
void esp_cache_err_int_init(void);

View File

@@ -0,0 +1,353 @@
// 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.
/* INTERNAL API
* generic interface to MMU memory protection features
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
MEMPROT_IRAM0 = 0x00000000,
MEMPROT_DRAM0 = 0x00000001,
MEMPROT_UNKNOWN
} mem_type_prot_t;
/**
* @brief Returns splitting address for required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Splitting address for the memory region required.
* The address is given by region-specific global symbol exported from linker script,
* it is not read out from related configuration register.
*/
uint32_t *IRAM_ATTR esp_memprot_get_split_addr(mem_type_prot_t mem_type);
/**
* @brief Initializes illegal memory access control (MMU) for required memory section.
*
* All memory access interrupts share ETS_MEMACCESS_ERR_INUM input channel, it is caller's
* responsibility to properly detect actual intr. source as well as possible prioritization in case
* of multiple source reported during one intr.handling routine run
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*/
void esp_memprot_intr_init(mem_type_prot_t mem_type);
/**
* @brief Enable/disable the memory protection interrupt
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param enable enable/disable
*/
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)
*
* @note When called without actual interrupt-on flag set, subsequent occurrence of related interrupt is ignored.
* Should be used only after the real interrupt appears, typically as the last step in interrupt handler's routine.
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*/
void esp_memprot_clear_intr(mem_type_prot_t mem_type);
/**
* @brief Detects which memory protection interrupt is active, check order: IRAM0, DRAM0
*
* @return Memory protection area type (see mem_type_prot_t enum)
*/
mem_type_prot_t IRAM_ATTR esp_memprot_get_intr_memtype(void);
/**
* @brief Gets interrupt status register contents for specified memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Contents of status register
*/
uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type);
/**
* @brief Get details of given interrupt status
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param faulting_address Faulting address causing the interrupt [out]
* @param op_type Operation being processed at the faulting address [out]
* IRAM0: 0 - read, 1 - write
* DRAM0: 0 - read, 1 - write
* @param op_subtype Additional info for op_type [out]
* IRAM0: 0 - instruction segment access, 1 - data segment access
* DRAM0: 0 - non-atomic operation, 1 - atomic operation
*/
void IRAM_ATTR esp_memprot_get_fault_status(mem_type_prot_t mem_type, uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype);
/**
* @brief Gets string representation of required memory region identifier
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return mem_type as string
*/
const char *IRAM_ATTR esp_memprot_type_to_str(mem_type_prot_t mem_type);
/**
* @brief Detects whether any of the interrupt locks is active (requires digital system reset to unlock)
*
* @return true/false
*/
bool esp_memprot_is_locked_any(void);
/**
* @brief Sets lock for specified memory region.
*
* Locks can be unlocked only by digital system reset
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*/
void esp_memprot_set_lock(mem_type_prot_t mem_type);
/**
* @brief Gets lock status for required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return true/false (locked/unlocked)
*/
bool esp_memprot_get_lock(mem_type_prot_t mem_type);
/**
* @brief Gets interrupt permission control register contents for required memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Permission control register contents
*/
uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type);
/**
* @brief Gets interrupt permission settings for unified management block
*
* Gets interrupt permission settings register contents for required memory region, returns settings for unified management blocks
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Permission settings register contents
*/
uint32_t esp_memprot_get_perm_uni_reg(mem_type_prot_t mem_type);
/**
* @brief Gets interrupt permission settings for split management block
*
* Gets interrupt permission settings register contents for required memory region, returns settings for split management blocks
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Permission settings register contents
*/
uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type);
/**
* @brief Detects whether any of the memory protection interrupts is enabled
*
* @return true/false
*/
bool esp_memprot_is_intr_ena_any(void);
/**
* @brief Gets interrupt-enabled flag for given memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Interrupt-enabled value
*/
uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type);
/**
* @brief Gets interrupt-active flag for given memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Interrupt-active value
*/
uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type);
/**
* @brief Gets interrupt-clear request flag for given memory region
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
*
* @return Interrupt-clear request value
*/
uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type);
/**
* @brief Gets read permission value for specified block and memory region
*
* Returns read permission bit value for required unified-management block (0-3) in given memory region.
* Applicable to all memory types.
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param block Memory block identifier (0-3)
*
* @return Read permission value for required block
*/
uint32_t esp_memprot_get_uni_block_read_bit(mem_type_prot_t mem_type, uint32_t block);
/**
* @brief Gets write permission value for specified block and memory region
*
* Returns write permission bit value for required unified-management block (0-3) in given memory region.
* Applicable to all memory types.
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param block Memory block identifier (0-3)
*
* @return Write permission value for required block
*/
uint32_t esp_memprot_get_uni_block_write_bit(mem_type_prot_t mem_type, uint32_t block);
/**
* @brief Gets execute permission value for specified block and memory region
*
* Returns execute permission bit value for required unified-management block (0-3) in given memory region.
* Applicable only to IRAM memory types
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param block Memory block identifier (0-3)
*
* @return Execute permission value for required block
*/
uint32_t esp_memprot_get_uni_block_exec_bit(mem_type_prot_t mem_type, uint32_t block);
/**
* @brief Sets permissions for specified block in DRAM region
*
* Sets Read and Write permission for specified unified-management block (0-3) in given memory region.
* Applicable only to DRAM memory types
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param block Memory block identifier (0-3)
* @param write_perm Write permission flag
* @param read_perm Read permission flag
*/
void esp_memprot_set_uni_block_perm_dram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm);
/**
* @brief Sets permissions for high and low memory segment in DRAM region
*
* Sets Read and Write permission for both low and high memory segments given by splitting address.
* The splitting address must be equal to or higher then beginning of block 5
* Applicable only to DRAM 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_dram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr);
/**
* @brief Sets permissions for specified block in IRAM region
*
* Sets Read, Write and Execute permission for specified unified-management block (0-3) in given memory region.
* Applicable only to IRAM memory types
*
* @param mem_type Memory protection area type (see mem_type_prot_t enum)
* @param block Memory block identifier (0-3)
* @param write_perm Write permission flag
* @param exec_perm Execute permission flag
*/
void esp_memprot_set_uni_block_perm_iram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm, bool exec_perm);
/**
* @brief Sets permissions for high and low memory segment in IRAM region
*
* Sets Read, Write and Execute permission for both low and high memory segments given by splitting address.
* The splitting address must be equal to or higher then beginning of block 5
* Applicable only to IRAM 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_iram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx);
/**
* @brief Activates memory protection for all supported memory region types
*
* @note The feature is disabled when JTAG interface is connected
*
* @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)
*/
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature);
/**
* @brief Get permission settings bits for IRAM split mgmt based on current split address
*
* @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_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
*
* @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_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr);
#ifdef __cplusplus
}
#endif

View File

@@ -160,6 +160,8 @@ SECTIONS
mapping[iram0_text]
/* align + add 16B for the possibly overlapping instructions */
. = ALIGN(4) + 16;
_iram_text_end = ABSOLUTE(.);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg

View File

@@ -0,0 +1,491 @@
// 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.
/* INTERNAL API
* implementation of generic interface to MMU memory protection features
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "soc/sensitive_reg.h"
#include "soc/dport_access.h"
#include "soc/periph_defs.h"
#include "esp_intr_alloc.h"
#include "esp32s2/memprot.h"
#include "hal/memprot_ll.h"
#include "esp_fault.h"
#include "esp_log.h"
extern int _iram_text_end;
extern int _data_start;
static const char *TAG = "memprot";
uint32_t *esp_memprot_iram0_get_min_split_addr(void)
{
return (uint32_t *)&_iram_text_end;
}
uint32_t *esp_memprot_dram0_get_min_split_addr(void)
{
return (uint32_t *)&_data_start;
}
uint32_t *esp_memprot_get_split_addr(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_min_split_addr();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_min_split_addr();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
const char *esp_memprot_type_to_str(mem_type_prot_t mem_type)
{
switch (mem_type) {
case MEMPROT_IRAM0:
return "IRAM0";
case MEMPROT_DRAM0:
return "DRAM0";
default:
return "UNKOWN";
}
}
void esp_memprot_intr_init(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM);
switch (mem_type) {
case MEMPROT_IRAM0:
intr_matrix_set(PRO_CPU_NUM, esp_memprot_iram0_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM);
break;
case MEMPROT_DRAM0:
intr_matrix_set(PRO_CPU_NUM, esp_memprot_dram0_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
ESP_INTR_ENABLE(ETS_MEMACCESS_ERR_INUM);
}
void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_intr_ena(enable);
break;
case MEMPROT_DRAM0:
esp_memprot_dram0_intr_ena(enable);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
bool esp_memprot_is_assoc_intr_any()
{
return esp_memprot_iram0_is_assoc_intr() || esp_memprot_dram0_is_assoc_intr();
}
mem_type_prot_t esp_memprot_get_intr_memtype()
{
if ( esp_memprot_is_assoc_intr(MEMPROT_IRAM0) ) {
return MEMPROT_IRAM0;
} else if ( esp_memprot_is_assoc_intr(MEMPROT_DRAM0) ) {
return MEMPROT_DRAM0;
}
return MEMPROT_UNKNOWN;
}
bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_is_assoc_intr();
case MEMPROT_DRAM0:
return esp_memprot_dram0_is_assoc_intr();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_clear_intr(mem_type_prot_t mem_type)
{
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_clear_intr();
break;
case MEMPROT_DRAM0:
esp_memprot_dram0_clear_intr();
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_set_lock(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_set_lock();
break;
case MEMPROT_DRAM0:
esp_memprot_dram0_set_lock();
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
bool esp_memprot_get_lock(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_lock_reg() > 0;
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_lock_reg() > 0;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
bool esp_memprot_is_locked_any()
{
return esp_memprot_iram0_get_lock_reg() > 0 || esp_memprot_iram0_get_lock_reg() > 0;
}
uint32_t esp_memprot_get_lock_bit(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_lock_bit();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_lock_bit();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_ena_reg();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_ena_reg();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_fault_reg();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_fault_reg();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_get_fault_status(mem_type_prot_t mem_type, uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_get_fault_status(faulting_address, op_type, op_subtype);
break;
case MEMPROT_DRAM0:
esp_memprot_dram0_get_fault_status(faulting_address, op_type, op_subtype);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
bool esp_memprot_is_intr_ena_any()
{
return esp_memprot_iram0_get_intr_ena_bit() > 0 || esp_memprot_dram0_get_intr_ena_bit() > 0;
}
uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_intr_ena_bit();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_intr_ena_bit();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_intr_on_bit();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_intr_on_bit();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_intr_clr_bit();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_intr_clr_bit();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_uni_block_read_bit(mem_type_prot_t mem_type, uint32_t block)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_uni_block_read_bit(block);
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_uni_block_read_bit(block);
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_uni_block_write_bit(mem_type_prot_t mem_type, uint32_t block)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_uni_block_write_bit(block);
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_uni_block_write_bit(block);
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_uni_block_exec_bit(mem_type_prot_t mem_type, uint32_t block)
{
assert(mem_type == MEMPROT_IRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_uni_block_exec_bit(block);
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_set_uni_block_perm_dram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm)
{
assert(mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_DRAM0:
esp_memprot_dram0_set_uni_block_perm(block, write_perm, read_perm);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_perm_uni_reg(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_perm_uni_reg();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_perm_reg();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type)
{
assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
return esp_memprot_iram0_get_perm_split_reg();
case MEMPROT_DRAM0:
return esp_memprot_dram0_get_perm_reg();
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_set_prot_dram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
{
assert(mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_DRAM0:
esp_memprot_dram0_set_prot(split_addr != NULL ? split_addr : esp_memprot_dram0_get_min_split_addr(), lw, lr, hw, hr);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_set_uni_block_perm_iram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm, bool exec_perm)
{
assert(mem_type == MEMPROT_IRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_set_uni_block_perm(block, write_perm, read_perm, exec_perm);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
assert(mem_type == MEMPROT_IRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_set_prot(split_addr != NULL ? split_addr : esp_memprot_iram0_get_min_split_addr(), lw, lr, lx, hw, hr, hx);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
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)
{
assert(mem_type == MEMPROT_IRAM0);
switch (mem_type) {
case MEMPROT_IRAM0:
esp_memprot_iram0_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx);
break;
default:
assert(0);
}
}
void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr)
{
assert(mem_type == MEMPROT_DRAM0);
switch (mem_type) {
case MEMPROT_DRAM0:
esp_memprot_dram0_get_split_sgnf_bits(lw, lr, hw, hr);
break;
default:
ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
abort();
}
}
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature)
{
esp_memprot_intr_ena(MEMPROT_DRAM0, false);
esp_memprot_intr_ena(MEMPROT_IRAM0, false);
if (!esp_cpu_in_ocd_debug_mode()) {
ESP_FAULT_ASSERT(!esp_cpu_in_ocd_debug_mode());
if ( invoke_panic_handler ) {
esp_memprot_intr_init(MEMPROT_DRAM0);
esp_memprot_intr_init(MEMPROT_IRAM0);
}
esp_memprot_set_prot_dram(MEMPROT_DRAM0, NULL, false, true, true, true);
esp_memprot_set_prot_iram(MEMPROT_IRAM0, NULL, false, true, true, true, true, false);
esp_memprot_intr_ena(MEMPROT_DRAM0, true);
esp_memprot_intr_ena(MEMPROT_IRAM0, true);
if ( lock_feature ) {
esp_memprot_set_lock(MEMPROT_DRAM0);
esp_memprot_set_lock(MEMPROT_IRAM0);
}
}
}