OVMS3-idf/components/soc/include/soc/soc_memory_layout.h
Angus Gratton 32756b165e bootloader: Add fault injection resistance to Secure Boot bootloader verification
Goal is that multiple faults would be required to bypass a boot-time signature check.

- Also strengthens some address range checks for safe app memory addresses
- Change pre-enable logic to also check the bootloader signature before enabling SBV2 on ESP32

Add some additional checks for invalid sections:

- Sections only partially in DRAM or IRAM are invalid
- If a section is in D/IRAM, allow the possibility only some is in D/IRAM
- Only pass sections that are entirely in the same type of RTC memory region
2020-03-06 01:16:04 +05:30

259 lines
9.8 KiB
C

// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "sdkconfig.h"
#include "esp_attr.h"
#ifdef CONFIG_BT_ENABLED
#define SOC_MEM_BT_DATA_START 0x3ffae6e0
#define SOC_MEM_BT_DATA_END 0x3ffaff10
#define SOC_MEM_BT_EM_START 0x3ffb0000
#define SOC_MEM_BT_EM_END 0x3ffb7cd8
#define SOC_MEM_BT_EM_BTDM0_START 0x3ffb0000
#define SOC_MEM_BT_EM_BTDM0_END 0x3ffb09a8
#define SOC_MEM_BT_EM_BLE_START 0x3ffb09a8
#define SOC_MEM_BT_EM_BLE_END 0x3ffb1ddc
#define SOC_MEM_BT_EM_BTDM1_START 0x3ffb1ddc
#define SOC_MEM_BT_EM_BTDM1_END 0x3ffb2730
#define SOC_MEM_BT_EM_BREDR_START 0x3ffb2730
#define SOC_MEM_BT_EM_BREDR_NO_SYNC_END 0x3ffb6388 //Not calculate with synchronize connection support
#define SOC_MEM_BT_EM_BREDR_END 0x3ffb7cd8 //Calculate with synchronize connection support
#define SOC_MEM_BT_EM_SYNC0_START 0x3ffb6388
#define SOC_MEM_BT_EM_SYNC0_END 0x3ffb6bf8
#define SOC_MEM_BT_EM_SYNC1_START 0x3ffb6bf8
#define SOC_MEM_BT_EM_SYNC1_END 0x3ffb7468
#define SOC_MEM_BT_EM_SYNC2_START 0x3ffb7468
#define SOC_MEM_BT_EM_SYNC2_END 0x3ffb7cd8
#define SOC_MEM_BT_BSS_START 0x3ffb8000
#define SOC_MEM_BT_BSS_END 0x3ffb9a20
#define SOC_MEM_BT_MISC_START 0x3ffbdb28
#define SOC_MEM_BT_MISC_END 0x3ffbdb5c
#define SOC_MEM_BT_EM_PER_SYNC_SIZE 0x870
#define SOC_MEM_BT_EM_BREDR_REAL_END (SOC_MEM_BT_EM_BREDR_NO_SYNC_END + CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF * SOC_MEM_BT_EM_PER_SYNC_SIZE)
#endif //CONFIG_BT_ENABLED
#define SOC_MEMORY_TYPE_NO_PRIOS 3
/* Type descriptor holds a description for a particular type of memory on a particular SoC.
*/
typedef struct {
const char *name; ///< Name of this memory type
uint32_t caps[SOC_MEMORY_TYPE_NO_PRIOS]; ///< Capabilities for this memory type (as a prioritised set)
bool aliased_iram; ///< If true, this is data memory that is is also mapped in IRAM
bool startup_stack; ///< If true, memory of this type is used for ROM stack during startup
} soc_memory_type_desc_t;
/* Constant table of tag descriptors for all this SoC's tags */
extern const soc_memory_type_desc_t soc_memory_types[];
extern const size_t soc_memory_type_count;
/* Region descriptor holds a description for a particular region of memory on a particular SoC.
*/
typedef struct
{
intptr_t start; ///< Start address of the region
size_t size; ///< Size of the region in bytes
size_t type; ///< Type of the region (index into soc_memory_types array)
intptr_t iram_address; ///< If non-zero, is equivalent address in IRAM
} soc_memory_region_t;
extern const soc_memory_region_t soc_memory_regions[];
extern const size_t soc_memory_region_count;
/* Region descriptor holds a description for a particular region of
memory reserved on this SoC for a particular use (ie not available
for stack/heap usage.) */
typedef struct
{
intptr_t start;
intptr_t end;
} soc_reserved_region_t;
/* Use this macro to reserved a fixed region of RAM (hardcoded addresses)
* for a particular purpose.
*
* Usually used to mark out memory addresses needed for hardware or ROM code
* purposes.
*
* Don't call this macro from user code which can use normal C static allocation
* instead.
*
* @param START Start address to be reserved.
* @param END One after the address of the last byte to be reserved. (ie length of
* the reserved region is (END - START) in bytes.
* @param NAME Name for the reserved region. Must be a valid variable name,
* unique to this source file.
*/
#define SOC_RESERVE_MEMORY_REGION(START, END, NAME) \
__attribute__((section(".reserved_memory_address"))) __attribute__((used)) \
static soc_reserved_region_t reserved_region_##NAME = { START, END };
/* Return available memory regions for this SoC. Each available memory
* region is a contiguous piece of memory which is not being used by
* static data, used by ROM code, or reserved by a component using
* the SOC_RESERVE_MEMORY_REGION() macro.
*
* This result is soc_memory_regions[] minus all regions reserved
* via the SOC_RESERVE_MEMORY_REGION() macro (which may also split
* some regions up.)
*
* At startup, all available memory returned by this function is
* registered as heap space.
*
* @note OS-level startup function only, not recommended to call from
* app code.
*
* @param regions Pointer to an array for reading available regions into.
* Size of the array should be at least the result of
* soc_get_available_memory_region_max_count(). Entries in the array
* will be ordered by memory address.
*
* @return Number of entries copied to 'regions'. Will be no greater than
* the result of soc_get_available_memory_region_max_count().
*/
size_t soc_get_available_memory_regions(soc_memory_region_t *regions);
/* Return the maximum number of available memory regions which could be
* returned by soc_get_available_memory_regions(). Used to size the
* array passed to that function.
*/
size_t soc_get_available_memory_region_max_count(void);
inline static bool IRAM_ATTR esp_ptr_dma_capable(const void *p)
{
return (intptr_t)p >= SOC_DMA_LOW && (intptr_t)p < SOC_DMA_HIGH;
}
inline static bool IRAM_ATTR esp_ptr_word_aligned(const void *p)
{
return ((intptr_t)p) % 4 == 0;
}
inline static bool IRAM_ATTR esp_ptr_executable(const void *p)
{
intptr_t ip = (intptr_t) p;
return (ip >= SOC_IROM_LOW && ip < SOC_IROM_HIGH)
|| (ip >= SOC_IRAM_LOW && ip < SOC_IRAM_HIGH)
|| (ip >= SOC_IROM_MASK_LOW && ip < SOC_IROM_MASK_HIGH)
#if defined(SOC_CACHE_APP_LOW) && defined(CONFIG_FREERTOS_UNICORE)
|| (ip >= SOC_CACHE_APP_LOW && ip < SOC_CACHE_APP_HIGH)
#endif
|| (ip >= SOC_RTC_IRAM_LOW && ip < SOC_RTC_IRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_byte_accessible(const void *p)
{
intptr_t ip = (intptr_t) p;
bool r;
r = (ip >= SOC_BYTE_ACCESSIBLE_LOW && ip < SOC_BYTE_ACCESSIBLE_HIGH);
#if CONFIG_SPIRAM
#if CONFIG_SPIRAM_SIZE != -1 // Fixed size, can be more accurate
r |= (ip >= SOC_EXTRAM_DATA_LOW && ip < (SOC_EXTRAM_DATA_LOW + CONFIG_SPIRAM_SIZE));
#else
r |= (ip >= SOC_EXTRAM_DATA_LOW && ip < (SOC_EXTRAM_DATA_HIGH));
#endif
#endif
return r;
}
inline static bool IRAM_ATTR esp_ptr_internal(const void *p) {
bool r;
r = ((intptr_t)p >= SOC_MEM_INTERNAL_LOW && (intptr_t)p < SOC_MEM_INTERNAL_HIGH);
r |= ((intptr_t)p >= SOC_RTC_DATA_LOW && (intptr_t)p < SOC_RTC_DATA_HIGH);
return r;
}
inline static bool IRAM_ATTR esp_ptr_external_ram(const void *p) {
return ((intptr_t)p >= SOC_EXTRAM_DATA_LOW && (intptr_t)p < SOC_EXTRAM_DATA_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_iram(const void *p) {
#if !CONFIG_FREERTOS_UNICORE || CONFIG_IDF_TARGET_ESP32S2BETA
return ((intptr_t)p >= SOC_IRAM_LOW && (intptr_t)p < SOC_IRAM_HIGH);
#else
return ((intptr_t)p >= SOC_CACHE_APP_LOW && (intptr_t)p < SOC_IRAM_HIGH);
#endif
}
inline static bool IRAM_ATTR esp_ptr_in_drom(const void *p) {
return ((intptr_t)p >= SOC_DROM_LOW && (intptr_t)p < SOC_DROM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_dram(const void *p) {
return ((intptr_t)p >= SOC_DRAM_LOW && (intptr_t)p < SOC_DRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_diram_dram(const void *p) {
return ((intptr_t)p >= SOC_DIRAM_DRAM_LOW && (intptr_t)p < SOC_DIRAM_DRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_diram_iram(const void *p) {
return ((intptr_t)p >= SOC_DIRAM_IRAM_LOW && (intptr_t)p < SOC_DIRAM_IRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_rtc_iram_fast(const void *p) {
return ((intptr_t)p >= SOC_RTC_IRAM_LOW && (intptr_t)p < SOC_RTC_IRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_rtc_dram_fast(const void *p) {
return ((intptr_t)p >= SOC_RTC_DRAM_LOW && (intptr_t)p < SOC_RTC_DRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_rtc_slow(const void *p) {
return ((intptr_t)p >= SOC_RTC_DATA_LOW && (intptr_t)p < SOC_RTC_DATA_HIGH);
}
/* Convert a D/IRAM DRAM pointer to equivalent word address in IRAM
- Address must be word aligned
- Address must pass esp_ptr_in_diram_dram() test, or result will be invalid pointer
*/
inline static void * IRAM_ATTR esp_ptr_diram_dram_to_iram(const void *p) {
#if SOC_DIRAM_INVERTED
return (void *) ( SOC_DIRAM_IRAM_LOW + (SOC_DIRAM_DRAM_HIGH - (intptr_t)p) - 4);
#else
return (void *) ( SOC_DIRAM_IRAM_LOW + ((intptr_t)p - SOC_DIRAM_DRAM_LOW) );
#endif
}
/* Convert a D/IRAM IRAM pointer to equivalent word address in DRAM
- Address must be word aligned
- Address must pass esp_ptr_in_diram_iram() test, or result will be invalid pointer
*/
inline static void * IRAM_ATTR esp_ptr_diram_iram_to_dram(const void *p) {
#if SOC_DIRAM_INVERTED
return (void *) ( SOC_DIRAM_DRAM_LOW + (SOC_DIRAM_IRAM_HIGH - (intptr_t)p) - 4);
#else
return (void *) ( SOC_DIRAM_DRAM_LOW + ((intptr_t)p - SOC_DIRAM_IRAM_LOW) );
#endif
}
inline static bool IRAM_ATTR esp_stack_ptr_is_sane(uint32_t sp)
{
//Check if stack ptr is in between SOC_DRAM_LOW and SOC_DRAM_HIGH, and 16 byte aligned.
return !(sp < SOC_DRAM_LOW + 0x10 || sp > SOC_DRAM_HIGH - 0x10 || ((sp & 0xF) != 0));
}