mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
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:
@@ -12,6 +12,7 @@ else()
|
||||
# Regular app build
|
||||
|
||||
set(srcs "cache_err_int.c"
|
||||
"memprot.c"
|
||||
"clk.c"
|
||||
"cpu_start.c"
|
||||
"crosscore_int.c"
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
|
353
components/esp32s2/include/esp32s2/memprot.h
Normal file
353
components/esp32s2/include/esp32s2/memprot.h
Normal 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
|
@@ -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
|
||||
|
491
components/esp32s2/memprot.c
Normal file
491
components/esp32s2/memprot.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user