mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-14 09:39:05 +01:00
Security: ESP32C3 memory protection feature (IRAM0/DRAM0)
Software support for PMS module. Allows controlled memory access to IRAM (R/W/X) and DRAM0 (R/W) On/locked by default, configurable in Kconfig (esp_system) Closes https://jira.espressif.com:8443/browse/IDF-2092
This commit is contained in:
@@ -19,6 +19,7 @@ else()
|
||||
"esp_ds.c"
|
||||
"esp_crypto_lock.c"
|
||||
"hw_random.c"
|
||||
"memprot.c"
|
||||
"system_api_esp32c3.c")
|
||||
set(include_dirs "include")
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
|
||||
|
||||
/* INTERNAL API
|
||||
* generic interface to MMU memory protection features
|
||||
* generic interface to PMS memory protection features
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -27,329 +27,67 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
MEMPROT_IRAM0 = 0x00000000,
|
||||
MEMPROT_DRAM0 = 0x00000001,
|
||||
MEMPROT_UNKNOWN
|
||||
MEMPROT_NONE = 0x00000000,
|
||||
MEMPROT_IRAM0_SRAM = 0x00000001,
|
||||
MEMPROT_DRAM0_SRAM = 0x00000002,
|
||||
MEMPROT_ALL = 0xFFFFFFFF
|
||||
} mem_type_prot_t;
|
||||
|
||||
typedef enum {
|
||||
MEMPROT_IRAM0_DRAM0_SPLITLINE,
|
||||
MEMPROT_IRAM0_LINE_0_SPLITLINE,
|
||||
MEMPROT_IRAM0_LINE_1_SPLITLINE,
|
||||
MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE,
|
||||
MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE
|
||||
} split_line_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);
|
||||
typedef enum {
|
||||
MEMPROT_IRAM0_PMS_AREA_0,
|
||||
MEMPROT_IRAM0_PMS_AREA_1,
|
||||
MEMPROT_IRAM0_PMS_AREA_2,
|
||||
MEMPROT_IRAM0_PMS_AREA_3,
|
||||
MEMPROT_DRAM0_PMS_AREA_0,
|
||||
MEMPROT_DRAM0_PMS_AREA_1,
|
||||
MEMPROT_DRAM0_PMS_AREA_2,
|
||||
MEMPROT_DRAM0_PMS_AREA_3
|
||||
} pms_area_t;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
const char *mem_type_to_str(mem_type_prot_t mem_type);
|
||||
const char *split_line_to_str(split_line_t line_type);
|
||||
const char *pms_to_str(pms_area_t area_type);
|
||||
|
||||
/**
|
||||
* @brief Detects whether any of the memory protection interrupts is active
|
||||
*
|
||||
* @return true/false
|
||||
*/
|
||||
bool esp_memprot_is_assoc_intr_any(void);
|
||||
void *esp_memprot_get_main_split_addr(void);
|
||||
void esp_memprot_set_split_line_lock(bool lock);
|
||||
bool esp_memprot_get_split_line_lock(void);
|
||||
void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock);
|
||||
bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type);
|
||||
void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x);
|
||||
void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type, bool lock);
|
||||
bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type);
|
||||
void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable);
|
||||
bool esp_memprot_get_monitor_en(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);
|
||||
int IRAM_ATTR esp_memprot_intr_get_cpuid(void);
|
||||
void IRAM_ATTR esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type);
|
||||
mem_type_prot_t IRAM_ATTR esp_memprot_get_active_intr_memtype(void);
|
||||
bool IRAM_ATTR esp_memprot_is_locked_any(void);
|
||||
bool IRAM_ATTR esp_memprot_is_intr_ena_any(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);
|
||||
uint32_t IRAM_ATTR esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type);
|
||||
uint32_t IRAM_ATTR esp_memprot_get_violate_addr(mem_type_prot_t mem_type);
|
||||
uint32_t IRAM_ATTR esp_memprot_get_violate_world(mem_type_prot_t mem_type);
|
||||
uint32_t IRAM_ATTR esp_memprot_get_violate_wr(mem_type_prot_t mem_type);
|
||||
uint32_t IRAM_ATTR esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type);
|
||||
uint32_t IRAM_ATTR esp_memprot_get_violate_byte_en(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);
|
||||
void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type);
|
||||
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask);
|
||||
void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -359,7 +359,8 @@ SECTIONS
|
||||
/* Marks the end of IRAM code segment */
|
||||
.iram0.text_end (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
/* C3 memprot requires 512 B alignment for split lines */
|
||||
. = ALIGN (0x200);
|
||||
_iram_text_end = ABSOLUTE(.);
|
||||
} > iram0_0_seg
|
||||
|
||||
|
||||
520
components/esp32c3/memprot.c
Normal file
520
components/esp32c3/memprot.c
Normal file
@@ -0,0 +1,520 @@
|
||||
// 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 PMS memory protection features
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/sensitive_reg.h"
|
||||
#include "soc/dport_access.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
static const char *TAG = "memprot";
|
||||
|
||||
#include "esp32c3/memprot.h"
|
||||
#include "hal/memprot_ll.h"
|
||||
#include "riscv/interrupt.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
extern int _iram_text_end;
|
||||
|
||||
const char *mem_type_to_str(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch (mem_type) {
|
||||
case MEMPROT_NONE:
|
||||
return "MEMPROT_NONE";
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return "MEMPROT_IRAM0_SRAM";
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return "MEMPROT_DRAM0_SRAM";
|
||||
case MEMPROT_ALL:
|
||||
return "MEMPROT_ALL";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *split_line_to_str(split_line_t line_type)
|
||||
{
|
||||
switch (line_type) {
|
||||
case MEMPROT_IRAM0_DRAM0_SPLITLINE:
|
||||
return "MEMPROT_IRAM0_DRAM0_SPLITLINE";
|
||||
case MEMPROT_IRAM0_LINE_0_SPLITLINE:
|
||||
return "MEMPROT_IRAM0_LINE_0_SPLITLINE";
|
||||
case MEMPROT_IRAM0_LINE_1_SPLITLINE:
|
||||
return "MEMPROT_IRAM0_LINE_1_SPLITLINE";
|
||||
case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE:
|
||||
return "MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE";
|
||||
case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE:
|
||||
return "MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *pms_to_str(pms_area_t area_type)
|
||||
{
|
||||
switch (area_type) {
|
||||
case MEMPROT_IRAM0_PMS_AREA_0:
|
||||
return "MEMPROT_IRAM0_PMS_AREA_0";
|
||||
case MEMPROT_IRAM0_PMS_AREA_1:
|
||||
return "MEMPROT_IRAM0_PMS_AREA_1";
|
||||
case MEMPROT_IRAM0_PMS_AREA_2:
|
||||
return "MEMPROT_IRAM0_PMS_AREA_2";
|
||||
case MEMPROT_IRAM0_PMS_AREA_3:
|
||||
return "MEMPROT_IRAM0_PMS_AREA_3";
|
||||
case MEMPROT_DRAM0_PMS_AREA_0:
|
||||
return "MEMPROT_DRAM0_PMS_AREA_0";
|
||||
case MEMPROT_DRAM0_PMS_AREA_1:
|
||||
return "MEMPROT_DRAM0_PMS_AREA_1";
|
||||
case MEMPROT_DRAM0_PMS_AREA_2:
|
||||
return "MEMPROT_DRAM0_PMS_AREA_2";
|
||||
case MEMPROT_DRAM0_PMS_AREA_3:
|
||||
return "MEMPROT_DRAM0_PMS_AREA_3";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* split lines */
|
||||
|
||||
void *esp_memprot_get_main_split_addr()
|
||||
{
|
||||
return &_iram_text_end;
|
||||
}
|
||||
|
||||
void esp_memprot_set_split_line_lock(bool lock)
|
||||
{
|
||||
memprot_ll_set_iram0_dram0_split_line_lock(lock);
|
||||
}
|
||||
|
||||
bool esp_memprot_get_split_line_lock()
|
||||
{
|
||||
return memprot_ll_get_iram0_dram0_split_line_lock();
|
||||
}
|
||||
|
||||
void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr)
|
||||
{
|
||||
uint32_t addr = (uint32_t)line_addr;
|
||||
ESP_LOGD(TAG, "Setting split line %s, addr: 0x%08X", split_line_to_str(line_type), addr);
|
||||
|
||||
//split-line must be divisible by 512
|
||||
assert( addr % 0x200 == 0 );
|
||||
|
||||
switch ( line_type ) {
|
||||
case MEMPROT_IRAM0_DRAM0_SPLITLINE:
|
||||
memprot_ll_set_iram0_split_line_main_I_D(line_addr);
|
||||
break;
|
||||
case MEMPROT_IRAM0_LINE_0_SPLITLINE:
|
||||
memprot_ll_set_iram0_split_line_I_0(line_addr);
|
||||
break;
|
||||
case MEMPROT_IRAM0_LINE_1_SPLITLINE:
|
||||
memprot_ll_set_iram0_split_line_I_1(line_addr);
|
||||
break;
|
||||
case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE:
|
||||
memprot_ll_set_dram0_split_line_D_0(line_addr);
|
||||
break;
|
||||
case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE:
|
||||
memprot_ll_set_dram0_split_line_D_1(line_addr);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid split line type, aborting: 0x%08X", addr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - get split lines
|
||||
|
||||
|
||||
/* PMS */
|
||||
|
||||
void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_set_pms_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false");
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
memprot_ll_iram0_set_pms_lock(lock);
|
||||
break;
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
memprot_ll_dram0_set_pms_lock(lock);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_get_pms_lock(%s)", mem_type_to_str(mem_type));
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_pms_lock();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_pms_lock();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_iram_set_pms_area(area:%s r:%u w:%u, x:%u)", pms_to_str(area_type), r, w, x);
|
||||
|
||||
switch ( area_type ) {
|
||||
case MEMPROT_IRAM0_PMS_AREA_0:
|
||||
memprot_ll_iram0_set_pms_area_0(r, w, x);
|
||||
break;
|
||||
case MEMPROT_IRAM0_PMS_AREA_1:
|
||||
memprot_ll_iram0_set_pms_area_1(r, w, x);
|
||||
break;
|
||||
case MEMPROT_IRAM0_PMS_AREA_2:
|
||||
memprot_ll_iram0_set_pms_area_2(r, w, x);
|
||||
break;
|
||||
case MEMPROT_IRAM0_PMS_AREA_3:
|
||||
memprot_ll_iram0_set_pms_area_3(r, w, x);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_dram_set_pms_area(area:%s r:%u w:%u)", pms_to_str(area_type), r, w);
|
||||
|
||||
switch ( area_type ) {
|
||||
case MEMPROT_DRAM0_PMS_AREA_0:
|
||||
memprot_ll_dram0_set_pms_area_0(r, w);
|
||||
break;
|
||||
case MEMPROT_DRAM0_PMS_AREA_1:
|
||||
memprot_ll_dram0_set_pms_area_1(r, w);
|
||||
break;
|
||||
case MEMPROT_DRAM0_PMS_AREA_2:
|
||||
memprot_ll_dram0_set_pms_area_2(r, w);
|
||||
break;
|
||||
case MEMPROT_DRAM0_PMS_AREA_3:
|
||||
memprot_ll_dram0_set_pms_area_3(r, w);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO - get single areas */
|
||||
|
||||
|
||||
/* monitor */
|
||||
|
||||
void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type, bool lock)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_set_monitor_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false");
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
memprot_ll_iram0_set_monitor_lock(lock);
|
||||
break;
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
memprot_ll_dram0_set_monitor_lock(lock);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_get_monitor_lock(%s)", mem_type_to_str(mem_type));
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_lock();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_lock();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type));
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
memprot_ll_iram0_set_monitor_en(enable);
|
||||
break;
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
memprot_ll_dram0_set_monitor_en(enable);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type));
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_en();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_en();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool esp_memprot_is_intr_ena_any()
|
||||
{
|
||||
return esp_memprot_get_monitor_en(MEMPROT_IRAM0_SRAM) || esp_memprot_get_monitor_en(MEMPROT_DRAM0_SRAM);
|
||||
}
|
||||
|
||||
void esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_monitor_clear_intr(%s)", mem_type_to_str(mem_type));
|
||||
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
memprot_ll_iram0_clear_monitor_intr();
|
||||
break;
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
memprot_ll_dram0_clear_monitor_intr();
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
mem_type_prot_t esp_memprot_get_active_intr_memtype()
|
||||
{
|
||||
if ( memprot_ll_iram0_get_monitor_status_intr() > 0 ) {
|
||||
return MEMPROT_IRAM0_SRAM;
|
||||
} else if ( memprot_ll_dram0_get_monitor_status_intr() ) {
|
||||
return MEMPROT_DRAM0_SRAM;
|
||||
}
|
||||
|
||||
return MEMPROT_NONE;
|
||||
}
|
||||
|
||||
bool esp_memprot_is_locked_any()
|
||||
{
|
||||
return
|
||||
esp_memprot_get_split_line_lock() ||
|
||||
esp_memprot_get_pms_lock(MEMPROT_IRAM0_SRAM) ||
|
||||
esp_memprot_get_pms_lock(MEMPROT_DRAM0_SRAM) ||
|
||||
esp_memprot_get_monitor_lock(MEMPROT_IRAM0_SRAM) ||
|
||||
esp_memprot_get_monitor_lock(MEMPROT_DRAM0_SRAM);
|
||||
}
|
||||
|
||||
uint32_t esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_status_intr();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_status_intr();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t esp_memprot_get_violate_addr(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_status_fault_addr();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_status_fault_addr();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t esp_memprot_get_violate_world(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_status_fault_world();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_status_fault_world();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t esp_memprot_get_violate_wr(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_status_fault_wr();
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_status_fault_wr();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
return memprot_ll_iram0_get_monitor_status_fault_loadstore();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type)
|
||||
{
|
||||
switch ( mem_type ) {
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
return memprot_ll_dram0_get_monitor_status_fault_byte_en();
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int esp_memprot_intr_get_cpuid()
|
||||
{
|
||||
return PRO_CPU_NUM;
|
||||
}
|
||||
|
||||
void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_set_intr_matrix(%s)", mem_type_to_str(mem_type));
|
||||
|
||||
ESP_INTR_DISABLE(ETS_MEMPROT_ERR_INUM);
|
||||
|
||||
switch (mem_type) {
|
||||
case MEMPROT_IRAM0_SRAM:
|
||||
intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_iram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM);
|
||||
break;
|
||||
case MEMPROT_DRAM0_SRAM:
|
||||
intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_dram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Set the type and priority to cache error interrupts. */
|
||||
esprv_intc_int_set_type(BIT(ETS_MEMPROT_ERR_INUM), INTR_TYPE_LEVEL);
|
||||
esprv_intc_int_set_priority(ETS_MEMPROT_ERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
||||
|
||||
ESP_INTR_ENABLE(ETS_MEMPROT_ERR_INUM);
|
||||
}
|
||||
|
||||
void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask)
|
||||
{
|
||||
esp_memprot_set_prot_int(invoke_panic_handler, lock_feature, NULL, mem_type_mask);
|
||||
}
|
||||
|
||||
void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask)
|
||||
{
|
||||
ESP_LOGD(TAG, "esp_memprot_set_prot(panic_handler: %u, lock: %u, split.addr: 0x%08X, mem.types: 0x%08X", invoke_panic_handler, lock_feature, (uint32_t)split_addr, (uint32_t)mem_type_mask);
|
||||
|
||||
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;
|
||||
bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM;
|
||||
|
||||
if (required_mem_prot == MEMPROT_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
//disable protection
|
||||
if (use_iram0) {
|
||||
esp_memprot_set_monitor_en(MEMPROT_IRAM0_SRAM, false);
|
||||
}
|
||||
if (use_dram0) {
|
||||
esp_memprot_set_monitor_en(MEMPROT_DRAM0_SRAM, false);
|
||||
}
|
||||
|
||||
//panic handling
|
||||
if (invoke_panic_handler) {
|
||||
if (use_iram0) {
|
||||
esp_memprot_set_intr_matrix(MEMPROT_IRAM0_SRAM);
|
||||
}
|
||||
if (use_dram0) {
|
||||
esp_memprot_set_intr_matrix(MEMPROT_DRAM0_SRAM);
|
||||
}
|
||||
}
|
||||
|
||||
//set split lines (must-have for all mem_types)
|
||||
const void *line_addr = split_addr == NULL ? esp_memprot_get_main_split_addr() : split_addr;
|
||||
esp_memprot_set_split_line(MEMPROT_IRAM0_LINE_1_SPLITLINE, line_addr);
|
||||
esp_memprot_set_split_line(MEMPROT_IRAM0_LINE_0_SPLITLINE, line_addr);
|
||||
esp_memprot_set_split_line(MEMPROT_IRAM0_DRAM0_SPLITLINE, line_addr);
|
||||
esp_memprot_set_split_line(MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE, (void *)(MAP_IRAM_TO_DRAM((uint32_t)line_addr)));
|
||||
esp_memprot_set_split_line(MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE, (void *)(MAP_IRAM_TO_DRAM((uint32_t)line_addr)));
|
||||
|
||||
//set permissions
|
||||
if (required_mem_prot & MEMPROT_IRAM0_SRAM) {
|
||||
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_0, true, false, true);
|
||||
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_1, true, false, true);
|
||||
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_2, true, false, true);
|
||||
esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_3, true, true, false);
|
||||
}
|
||||
if (required_mem_prot & MEMPROT_DRAM0_SRAM) {
|
||||
esp_memprot_dram_set_pms_area( MEMPROT_DRAM0_PMS_AREA_0, true, false );
|
||||
esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_1, true, true);
|
||||
esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_2, true, true);
|
||||
esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_3, true, true);
|
||||
}
|
||||
|
||||
//reenable protection
|
||||
if (use_iram0) {
|
||||
esp_memprot_monitor_clear_intr(MEMPROT_IRAM0_SRAM);
|
||||
esp_memprot_set_monitor_en(MEMPROT_IRAM0_SRAM, true);
|
||||
}
|
||||
if (use_dram0) {
|
||||
esp_memprot_monitor_clear_intr(MEMPROT_DRAM0_SRAM);
|
||||
esp_memprot_set_monitor_en(MEMPROT_DRAM0_SRAM, true);
|
||||
}
|
||||
|
||||
//lock if required
|
||||
if (lock_feature) {
|
||||
esp_memprot_set_split_line_lock(true);
|
||||
if (use_iram0) {
|
||||
esp_memprot_set_pms_lock(MEMPROT_IRAM0_SRAM, true);
|
||||
esp_memprot_set_monitor_lock(MEMPROT_IRAM0_SRAM, true);
|
||||
}
|
||||
if (use_dram0) {
|
||||
esp_memprot_set_pms_lock(MEMPROT_DRAM0_SRAM, true);
|
||||
esp_memprot_set_monitor_lock(MEMPROT_DRAM0_SRAM, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user