diff --git a/components/esp32c3/CMakeLists.txt b/components/esp32c3/CMakeLists.txt new file mode 100644 index 0000000000..a0e34ea74d --- /dev/null +++ b/components/esp32c3/CMakeLists.txt @@ -0,0 +1,71 @@ +idf_build_get_property(target IDF_TARGET) +idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER) +if(NOT "${target}" STREQUAL "esp32c3") + return() +endif() + +if(BOOTLOADER_BUILD) + # For bootloader, all we need from esp32c3 is headers + idf_component_register(INCLUDE_DIRS include REQUIRES riscv) + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32c3.peripherals.ld") +else() + # Regular app build + + set(srcs "cache_err_int.c" + "clk.c" + "crosscore_int.c" + "dport_access.c" + "esp_hmac.c" + "esp_crypto_lock.c" + "hw_random.c" + "system_api_esp32c3.c") + set(include_dirs "include") + + set(requires driver efuse soc riscv) #unfortunately rom/uart uses SOC registers directly + + # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t + # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. + # esp_timer is added here because cpu_start.c uses esp_timer + set(priv_requires + app_trace app_update bootloader_support log mbedtls nvs_flash + pthread spi_flash vfs espcoredump esp_common esp_timer) + + set(fragments linker.lf ld/esp32c3_fragments.lf) + + idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS "${fragments}" + REQUIRES "${requires}" + PRIV_REQUIRES "${priv_requires}" + REQUIRED_IDF_TARGETS esp32c3) + + target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32c3_out.ld") + + # Process the template file through the linker script generation mechanism, and use the output for linking the + # final binary + target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32c3.project.ld.in" + PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32c3.project.ld") + + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32c3.peripherals.ld") + target_link_libraries(${COMPONENT_LIB} PUBLIC gcc) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0") + + idf_build_get_property(config_dir CONFIG_DIR) + # Preprocess esp32c3.ld linker script to include configuration, becomes esp32c3_out.ld + set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld) + add_custom_command( + OUTPUT esp32c3_out.ld + COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32c3_out.ld -I ${config_dir} ${LD_DIR}/esp32c3.ld + MAIN_DEPENDENCY ${LD_DIR}/esp32c3.ld ${sdkconfig_header} + COMMENT "Generating linker script..." + VERBATIM) + + add_custom_target(esp32c3_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32c3_out.ld) + add_dependencies(${COMPONENT_LIB} esp32c3_linker_script) + + # disable stack protection in files which are involved in initialization of that feature + set_source_files_properties( + cpu_start.c + PROPERTIES COMPILE_FLAGS + -fno-stack-protector) +endif() diff --git a/components/esp32c3/Kconfig b/components/esp32c3/Kconfig new file mode 100644 index 0000000000..617c158bfa --- /dev/null +++ b/components/esp32c3/Kconfig @@ -0,0 +1,219 @@ +menu "ESP32C3-Specific" + visible if IDF_TARGET_ESP32C3 + + choice ESP32C3_DEFAULT_CPU_FREQ_MHZ + prompt "CPU frequency" + default ESP32C3_DEFAULT_CPU_FREQ_40 if IDF_ENV_FPGA + default ESP32C3_DEFAULT_CPU_FREQ_160 if !IDF_ENV_FPGA + help + CPU frequency to be set on application startup. + + config ESP32C3_DEFAULT_CPU_FREQ_40 + bool "40 MHz" + depends on IDF_ENV_FPGA + config ESP32C3_DEFAULT_CPU_FREQ_80 + bool "80 MHz" + config ESP32C3_DEFAULT_CPU_FREQ_160 + bool "160 MHz" + endchoice + + config ESP32C3_DEFAULT_CPU_FREQ_MHZ + int + default 40 if ESP32C3_DEFAULT_CPU_FREQ_40 + default 80 if ESP32C3_DEFAULT_CPU_FREQ_80 + default 160 if ESP32C3_DEFAULT_CPU_FREQ_160 + + choice ESP32C3_UNIVERSAL_MAC_ADDRESSES + bool "Number of universally administered (by IEEE) MAC address" + default ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO + help + Configure the number of universally administered (by IEEE) MAC addresses. + During initialization, MAC addresses for each network interface are generated or derived from a + single base MAC address. + If the number of universal MAC addresses is Two, all interfaces (WiFi station, WiFi softap) receive a + universally administered MAC address. They are generated sequentially by adding 0, and 1 (respectively) + to the final octet of the base MAC address. If the number of universal MAC addresses is one, + only WiFi station receives a universally administered MAC address. + It's generated by adding 0 to the base MAC address. + The WiFi softap receives local MAC addresses. It's derived from the universal WiFi station MAC addresses. + When using the default (Espressif-assigned) base MAC address, either setting can be used. When using + a custom universal MAC address range, the correct setting will depend on the allocation of MAC + addresses in this range (either 1 or 2 per device.) + + config ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO + bool "Two" + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_BT + config ESP32C3_UNIVERSAL_MAC_ADDRESSES_THREE + bool "Three" + select ESP_MAC_ADDR_UNIVERSE_WIFI_STA + select ESP_MAC_ADDR_UNIVERSE_WIFI_AP + select ESP_MAC_ADDR_UNIVERSE_BT + endchoice + + config ESP32C3_UNIVERSAL_MAC_ADDRESSES + int + default 2 if ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO + default 3 if ESP32C3_UNIVERSAL_MAC_ADDRESSES_THREE + + config ESP_MAC_ADDR_UNIVERSE_BT_OFFSET + int + default 2 if ESP32C3_UNIVERSAL_MAC_ADDRESSES_THREE + default 1 if ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO + + config ESP32C3_DEBUG_OCDAWARE + bool "Make exception and panic handlers JTAG/OCD aware" + default y + select FREERTOS_DEBUG_OCDAWARE + help + The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and + instead of panicking, have the debugger stop on the offending instruction. + + config ESP32C3_DEBUG_STUBS_ENABLE + bool "OpenOCD debug stubs" + default COMPILER_OPTIMIZATION_LEVEL_DEBUG + depends on !ESP32C3_TRAX + help + Debug stubs are used by OpenOCD to execute pre-compiled onboard code which does some useful debugging, + e.g. GCOV data dump. + + config ESP32C3_BROWNOUT_DET + # TODO ESP32-C3 IDF-2397 + bool + default n + help + The ESP32-S3 has a built-in brownout detector which can detect if the voltage is lower than + a specific value. If this happens, it will reset the chip in order to prevent unintended + behaviour. + + choice ESP32C3_BROWNOUT_DET_LVL_SEL + prompt "Brownout voltage level" + depends on ESP32C3_BROWNOUT_DET + default ESP32C3_BROWNOUT_DET_LVL_SEL_7 + help + The brownout detector will reset the chip when the supply voltage is approximately + below this level. Note that there may be some variation of brownout voltage level + between each ESP3-S3 chip. + + #The voltage levels here are estimates, more work needs to be done to figure out the exact voltages + #of the brownout threshold levels. + config ESP32C3_BROWNOUT_DET_LVL_SEL_7 + bool "2.44V" + config ESP32C3_BROWNOUT_DET_LVL_SEL_6 + bool "2.56V" + config ESP32C3_BROWNOUT_DET_LVL_SEL_5 + bool "2.67V" + config ESP32C3_BROWNOUT_DET_LVL_SEL_4 + bool "2.84V" + config ESP32C3_BROWNOUT_DET_LVL_SEL_3 + bool "2.98V" + config ESP32C3_BROWNOUT_DET_LVL_SEL_2 + bool "3.19V" + config ESP32C3_BROWNOUT_DET_LVL_SEL_1 + bool "3.30V" + endchoice + + config ESP32C3_BROWNOUT_DET_LVL + int + default 1 if ESP32C3_BROWNOUT_DET_LVL_SEL_1 + default 2 if ESP32C3_BROWNOUT_DET_LVL_SEL_2 + default 3 if ESP32C3_BROWNOUT_DET_LVL_SEL_3 + default 4 if ESP32C3_BROWNOUT_DET_LVL_SEL_4 + default 5 if ESP32C3_BROWNOUT_DET_LVL_SEL_5 + default 6 if ESP32C3_BROWNOUT_DET_LVL_SEL_6 + default 7 if ESP32C3_BROWNOUT_DET_LVL_SEL_7 + + choice ESP32C3_TIME_SYSCALL + prompt "Timers used for gettimeofday function" + default ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER + help + This setting defines which hardware timers are used to + implement 'gettimeofday' and 'time' functions in C library. + + - If both high-resolution (systimer) and RTC timers are used, timekeeping will + continue in deep sleep. Time will be reported at 1 microsecond + resolution. This is the default, and the recommended option. + - If only high-resolution timer (systimer) is used, gettimeofday will + provide time at microsecond resolution. + Time will not be preserved when going into deep sleep mode. + - If only RTC timer is used, timekeeping will continue in + deep sleep, but time will be measured at 6.(6) microsecond + resolution. Also the gettimeofday function itself may take + longer to run. + - If no timers are used, gettimeofday and time functions + return -1 and set errno to ENOSYS. + - When RTC is used for timekeeping, two RTC_STORE registers are + used to keep time in deep sleep mode. + + config ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER + bool "RTC and high-resolution timer" + select ESP_TIME_FUNCS_USE_RTC_TIMER + select ESP_TIME_FUNCS_USE_ESP_TIMER + config ESP32C3_TIME_SYSCALL_USE_RTC + bool "RTC" + select ESP_TIME_FUNCS_USE_RTC_TIMER + config ESP32C3_TIME_SYSCALL_USE_SYSTIMER + bool "High-resolution timer" + select ESP_TIME_FUNCS_USE_ESP_TIMER + config ESP32C3_TIME_SYSCALL_USE_NONE + bool "None" + select ESP_TIME_FUNCS_USE_NONE + endchoice + + choice ESP32C3_RTC_CLK_SRC + prompt "RTC clock source" + default ESP32C3_RTC_CLK_SRC_INT_RC + help + Choose which clock is used as RTC clock source. + + config ESP32C3_RTC_CLK_SRC_INT_RC + bool "Internal 150kHz RC oscillator" + config ESP32C3_RTC_CLK_SRC_EXT_CRYS + bool "External 32kHz crystal" + select ESP_SYSTEM_RTC_EXT_XTAL + config ESP32C3_RTC_CLK_SRC_EXT_OSC + bool "External 32kHz oscillator at 32K_XP pin" + config ESP32C3_RTC_CLK_SRC_INT_8MD256 + bool "Internal 8MHz oscillator, divided by 256 (~32kHz)" + endchoice + + config ESP32C3_RTC_CLK_CAL_CYCLES + int "Number of cycles for RTC_SLOW_CLK calibration" + default 3000 if ESP32C3_RTC_CLK_SRC_EXT_CRYS || ESP32C3_RTC_CLK_SRC_EXT_OSC || ESP32C3_RTC_CLK_SRC_INT_8MD256 + default 1024 if ESP32C3_RTC_CLK_SRC_INT_RC + range 0 125000 + help + When the startup code initializes RTC_SLOW_CLK, it can perform + calibration by comparing the RTC_SLOW_CLK frequency with main XTAL + frequency. This option sets the number of RTC_SLOW_CLK cycles measured + by the calibration routine. Higher numbers increase calibration + precision, which may be important for applications which spend a lot of + time in deep sleep. Lower numbers reduce startup time. + + When this option is set to 0, clock calibration will not be performed at + startup, and approximate clock frequencies will be assumed: + + - 150000 Hz if internal RC oscillator is used as clock source. For this use value 1024. + - 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more. + In case more value will help improve the definition of the launch of the crystal. + If the crystal could not start, it will be switched to internal RC. + + config ESP32C3_NO_BLOBS + bool "No Binary Blobs" + depends on !BT_ENABLED + default n + help + If enabled, this disables the linking of binary libraries in the application build. Note + that after enabling this Wi-Fi/Bluetooth will not work. + + config ESP32C3_ALLOW_RTC_FAST_MEM_AS_HEAP + bool "Enable RTC fast memory for dynamic allocations" + depends on !ESP32C3_MEMPROT_FEATURE + default y + help + This config option allows to add RTC fast memory region to system heap with capability + similar to that of DRAM region but without DMA. This memory will be consumed first per + heap initialization order by early startup services and scheduler related code. Speed + wise RTC fast memory operates on APB clock and hence does not have much performance impact. + +endmenu # ESP32C3-Specific diff --git a/components/esp32c3/Makefile.projbuild b/components/esp32c3/Makefile.projbuild new file mode 100644 index 0000000000..cb10139573 --- /dev/null +++ b/components/esp32c3/Makefile.projbuild @@ -0,0 +1 @@ +# ESP32-C3 is not supported in the GNU Make build system. diff --git a/components/esp32c3/cache_err_int.c b/components/esp32c3/cache_err_int.c new file mode 100644 index 0000000000..3f675fb5e8 --- /dev/null +++ b/components/esp32c3/cache_err_int.c @@ -0,0 +1,34 @@ +// Copyright 2015-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. + +/* + The cache has an interrupt that can be raised as soon as an access to a cached + region (flash) is done without the cache being enabled. We use that here + to panic the CPU, which from a debugging perspective is better than grabbing bad + data from the bus. +*/ + +#include +#include "sdkconfig.h" +#include "esp_attr.h" + +// TODO ESP32-C3 IDF-2450 +void esp_cache_err_int_init(void) +{ +} + +int IRAM_ATTR esp_cache_err_get_cpuid(void) +{ + return 0; +} diff --git a/components/esp32c3/clk.c b/components/esp32c3/clk.c new file mode 100644 index 0000000000..978331a28b --- /dev/null +++ b/components/esp32c3/clk.c @@ -0,0 +1,38 @@ +// Copyright 2015-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. + +#include +#include + +#include "esp_attr.h" +#include "soc/rtc.h" +#include "esp32c3/clk.h" +#include "esp32c3/rom/ets_sys.h" + +#define MHZ (1000000) + +int IRAM_ATTR esp_clk_cpu_freq(void) +{ + return ets_get_cpu_frequency() * MHZ; +} + +int IRAM_ATTR esp_clk_apb_freq(void) +{ + return MIN(80, ets_get_cpu_frequency()) * MHZ; +} + +int IRAM_ATTR esp_clk_xtal_freq(void) +{ + return rtc_clk_xtal_freq_get() * MHZ; +} diff --git a/components/esp32c3/component.mk b/components/esp32c3/component.mk new file mode 100644 index 0000000000..a2f7dc1797 --- /dev/null +++ b/components/esp32c3/component.mk @@ -0,0 +1,4 @@ +# +# Component Makefile +# +COMPONENT_CONFIG_ONLY := 1 diff --git a/components/esp32c3/crosscore_int.c b/components/esp32c3/crosscore_int.c new file mode 100644 index 0000000000..dad7673969 --- /dev/null +++ b/components/esp32c3/crosscore_int.c @@ -0,0 +1,97 @@ +// Copyright 2015-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. +#include +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +#include "soc/system_reg.h" +#include "hal/cpu_hal.h" +#include "freertos/FreeRTOS.h" +#include "freertos/portmacro.h" + +#define REASON_YIELD BIT(0) +#define REASON_FREQ_SWITCH BIT(1) +#define REASON_PRINT_BACKTRACE BIT(2) + +static portMUX_TYPE reason_spinlock = portMUX_INITIALIZER_UNLOCKED; +static volatile uint32_t reason[portNUM_PROCESSORS]; + +// TODO ESP32-C3 IDF-2449 +static inline void IRAM_ATTR esp_crosscore_isr_handle_yield(void) +{ + portYIELD_FROM_ISR(); +} + +static void IRAM_ATTR esp_crosscore_isr(void *arg) +{ + uint32_t my_reason_val; + //A pointer to the correct reason array item is passed to this ISR. + volatile uint32_t *my_reason = arg; + + //Clear the interrupt first. + WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0); + //Grab the reason and clear it. + portENTER_CRITICAL_ISR(&reason_spinlock); + my_reason_val = *my_reason; + *my_reason = 0; + portEXIT_CRITICAL_ISR(&reason_spinlock); + + //Check what we need to do. + if (my_reason_val & REASON_YIELD) { + esp_crosscore_isr_handle_yield(); + } + if (my_reason_val & REASON_FREQ_SWITCH) { + /* Nothing to do here; the frequency switch event was already + * handled by a hook in xtensa_vectors.S. Could be used in the future + * to allow DFS features without the extra latency of the ISR hook. + */ + } +} + +// Initialize the crosscore interrupt on this core. +void esp_crosscore_int_init(void) +{ + portENTER_CRITICAL(&reason_spinlock); + reason[cpu_hal_get_core_id()] = 0; + portEXIT_CRITICAL(&reason_spinlock); + esp_err_t err = esp_intr_alloc(ETS_FROM_CPU_INTR0_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void *)&reason[0], NULL); + assert(err == ESP_OK); +} + +static void IRAM_ATTR esp_crosscore_int_send(int core_id, uint32_t reason_mask) +{ + assert(core_id < portNUM_PROCESSORS); + //Mark the reason we interrupt the other CPU + portENTER_CRITICAL(&reason_spinlock); + reason[core_id] |= reason_mask; + portEXIT_CRITICAL(&reason_spinlock); + //Poke the other CPU. + WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, SYSTEM_CPU_INTR_FROM_CPU_0); +} + +void IRAM_ATTR esp_crosscore_int_send_yield(int core_id) +{ + esp_crosscore_int_send(core_id, REASON_YIELD); +} + +void IRAM_ATTR esp_crosscore_int_send_freq_switch(int core_id) +{ + esp_crosscore_int_send(core_id, REASON_FREQ_SWITCH); +} + +void IRAM_ATTR esp_crosscore_int_send_print_backtrace(int core_id) +{ + esp_crosscore_int_send(core_id, REASON_PRINT_BACKTRACE); +} diff --git a/components/esp32c3/dport_access.c b/components/esp32c3/dport_access.c new file mode 100644 index 0000000000..08b55a96fb --- /dev/null +++ b/components/esp32c3/dport_access.c @@ -0,0 +1,25 @@ +// Copyright 2010-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. + +#include +#include +#include "soc/dport_access.h" + +// Read a sequence of DPORT registers to the buffer. +void esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address, uint32_t num_words) +{ + for (uint32_t i = 0; i < num_words; ++i) { + buff_out[i] = DPORT_SEQUENCE_REG_READ(address + i * 4); + } +} diff --git a/components/esp32c3/esp_crypto_lock.c b/components/esp32c3/esp_crypto_lock.c new file mode 100644 index 0000000000..ca6c3c49b9 --- /dev/null +++ b/components/esp32c3/esp_crypto_lock.c @@ -0,0 +1,98 @@ +// Copyright 2015-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. + +#include + +#include "esp_crypto_lock.h" + +/* Lock overview: +SHA: independent +AES: independent +MPI/RSA: independent +HMAC: needs SHA +DS: needs HMAC (which needs SHA), AES and MPI +*/ + +/* Lock for DS peripheral */ +static _lock_t s_crypto_ds_lock; + +/* Lock for HMAC peripheral */ +static _lock_t s_crypto_hmac_lock; + +/* Lock for the SHA peripheral, also used by the HMAC and DS peripheral */ +static _lock_t s_crypto_sha_lock; + +/* Lock for the AES peripheral, also used by DS peripheral */ +static _lock_t s_crypto_aes_lock; + +/* Lock for the MPI/RSA peripheral, also used by the DS peripheral */ +static _lock_t s_crypto_mpi_lock; + +void esp_crypto_hmac_lock_acquire(void) +{ + _lock_acquire(&s_crypto_hmac_lock); + esp_crypto_sha_lock_acquire(); +} + +void esp_crypto_hmac_lock_release(void) +{ + esp_crypto_sha_lock_release(); + _lock_release(&s_crypto_hmac_lock); +} + +void esp_crypto_ds_lock_acquire(void) +{ + _lock_acquire(&s_crypto_ds_lock); + esp_crypto_hmac_lock_acquire(); + esp_crypto_aes_lock_acquire(); + esp_crypto_mpi_lock_acquire(); +} + +void esp_crypto_ds_lock_release(void) +{ + esp_crypto_mpi_lock_release(); + esp_crypto_aes_lock_release(); + esp_crypto_hmac_lock_release(); + _lock_release(&s_crypto_ds_lock); +} + +void esp_crypto_sha_lock_acquire(void) +{ + _lock_acquire(&s_crypto_sha_lock); +} + +void esp_crypto_sha_lock_release(void) +{ + _lock_release(&s_crypto_sha_lock); +} + +void esp_crypto_aes_lock_acquire(void) +{ + _lock_acquire(&s_crypto_aes_lock); +} + +void esp_crypto_aes_lock_release(void) +{ + _lock_release(&s_crypto_aes_lock); +} + +void esp_crypto_mpi_lock_acquire(void) +{ + _lock_acquire(&s_crypto_mpi_lock); +} + +void esp_crypto_mpi_lock_release(void) +{ + _lock_release(&s_crypto_mpi_lock); +} diff --git a/components/esp32c3/esp_hmac.c b/components/esp32c3/esp_hmac.c new file mode 100644 index 0000000000..5ae936ced8 --- /dev/null +++ b/components/esp32c3/esp_hmac.c @@ -0,0 +1,132 @@ +// Copyright 2015-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. + +#include +#include "driver/periph_ctrl.h" +#include "esp32c3/rom/hmac.h" +#include "esp32c3/rom/ets_sys.h" +#include "esp_hmac.h" +#include "esp_crypto_lock.h" + +#include "hal/hmac_hal.h" + +#define SHA256_BLOCK_SZ 64 +#define SHA256_PAD_SZ 8 + +/** + * @brief Apply the HMAC padding without the embedded length. + * + * @note This function does not check the data length, it is the responsability of the other functions in this + * module to make sure that \c data_len is at most SHA256_BLOCK_SZ - 1 so the padding fits in. + * Otherwise, this function has undefined behavior. + * Note however, that for the actual HMAC implementation on ESP32C3, the length also needs to be applied at the end + * of the block. This function alone deosn't do that. + */ +static void write_and_padd(uint8_t *block, const uint8_t *data, uint16_t data_len) +{ + memcpy(block, data, data_len); + // Apply a one bit, followed by zero bits (refer to the ESP32C3 TRM). + block[data_len] = 0x80; + bzero(block + data_len + 1, SHA256_BLOCK_SZ - data_len - 1); +} + +esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, + const void *message, + size_t message_len, + uint8_t *hmac) +{ + const uint8_t *message_bytes = (const uint8_t *)message; + + if (!message || !hmac) { + return ESP_ERR_INVALID_ARG; + } + if (key_id >= HMAC_KEY_MAX) { + return ESP_ERR_INVALID_ARG; + } + + esp_crypto_hmac_lock_acquire(); + + // We also enable SHA and DS here. SHA is used by HMAC, DS will otherwise hold SHA in reset state. + periph_module_enable(PERIPH_HMAC_MODULE); + periph_module_enable(PERIPH_SHA_MODULE); + periph_module_enable(PERIPH_DS_MODULE); + + hmac_hal_start(); + + uint32_t conf_error = hmac_hal_configure(HMAC_OUTPUT_USER, key_id); + if (conf_error) { + esp_crypto_hmac_lock_release(); + return ESP_FAIL; + } + + if (message_len + 1 + SHA256_PAD_SZ <= SHA256_BLOCK_SZ) { + // If message including padding is only one block... + // Last message block, so apply SHA-256 padding rules in software + uint8_t block[SHA256_BLOCK_SZ]; + uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512); + + write_and_padd(block, message_bytes, message_len); + // Final block: append the bit length in this block and signal padding to peripheral + memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len), + &bit_len, sizeof(bit_len)); + hmac_hal_write_one_block_512(block); + } else { + // If message including padding is needs more than one block + + // write all blocks without padding except the last one + size_t remaining_blocks = message_len / SHA256_BLOCK_SZ; + for (int i = 1; i < remaining_blocks; i++) { + hmac_hal_write_block_512(message_bytes); + message_bytes += SHA256_BLOCK_SZ; + hmac_hal_next_block_normal(); + } + + // If message fits into one block but without padding, we must not write another block. + if (remaining_blocks) { + hmac_hal_write_block_512(message_bytes); + message_bytes += SHA256_BLOCK_SZ; + } + + size_t remaining = message_len % SHA256_BLOCK_SZ; + // Last message block, so apply SHA-256 padding rules in software + uint8_t block[SHA256_BLOCK_SZ]; + uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512); + + // If the remaining message and appended padding doesn't fit into a single block, we have to write an + // extra block with the rest of the message and potential padding first. + if (remaining >= SHA256_BLOCK_SZ - SHA256_PAD_SZ) { + write_and_padd(block, message_bytes, remaining); + hmac_hal_next_block_normal(); + hmac_hal_write_block_512(block); + bzero(block, SHA256_BLOCK_SZ); + } else { + write_and_padd(block, message_bytes, remaining); + } + memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len), + &bit_len, sizeof(bit_len)); + hmac_hal_next_block_padding(); + hmac_hal_write_block_512(block); + } + + // Read back result (bit swapped) + hmac_hal_read_result_256(hmac); + + periph_module_disable(PERIPH_DS_MODULE); + periph_module_disable(PERIPH_SHA_MODULE); + periph_module_disable(PERIPH_HMAC_MODULE); + + esp_crypto_hmac_lock_release(); + + return ESP_OK; +} diff --git a/components/esp32c3/hw_random.c b/components/esp32c3/hw_random.c new file mode 100644 index 0000000000..a437617c83 --- /dev/null +++ b/components/esp32c3/hw_random.c @@ -0,0 +1,68 @@ +// 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. + +#include +#include +#include +#include +#include "esp_attr.h" +#include "esp32c3/clk.h" +#include "soc/wdev_reg.h" +#include "hal/cpu_hal.h" + +uint32_t IRAM_ATTR esp_random(void) +{ + /* The PRNG which implements WDEV_RANDOM register gets 2 bits + * of extra entropy from a hardware randomness source every APB clock cycle + * (provided WiFi or BT are enabled). To make sure entropy is not drained + * faster than it is added, this function needs to wait for at least 16 APB + * clock cycles after reading previous word. This implementation may actually + * wait a bit longer due to extra time spent in arithmetic and branch statements. + * + * As a (probably unncessary) precaution to avoid returning the + * RNG state as-is, the result is XORed with additional + * WDEV_RND_REG reads while waiting. + */ + + /* This code does not run in a critical section, so CPU frequency switch may + * happens while this code runs (this will not happen in the current + * implementation, but possible in the future). However if that happens, + * the number of cycles spent on frequency switching will certainly be more + * than the number of cycles we need to wait here. + */ + uint32_t cpu_to_apb_freq_ratio = esp_clk_cpu_freq() / esp_clk_apb_freq(); + + static uint32_t last_ccount = 0; + uint32_t ccount; + uint32_t result = 0; + do { + ccount = cpu_hal_get_cycle_count(); + result ^= REG_READ(WDEV_RND_REG); + } while (ccount - last_ccount < cpu_to_apb_freq_ratio * 16); + last_ccount = ccount; + return result ^ REG_READ(WDEV_RND_REG); +} + +void esp_fill_random(void *buf, size_t len) +{ + assert(buf != NULL); + uint8_t *buf_bytes = (uint8_t *)buf; + while (len > 0) { + uint32_t word = esp_random(); + uint32_t to_copy = MIN(sizeof(word), len); + memcpy(buf_bytes, &word, to_copy); + buf_bytes += to_copy; + len -= to_copy; + } +} diff --git a/components/esp32c3/include/esp32c3/brownout.h b/components/esp32c3/include/esp32c3/brownout.h new file mode 100644 index 0000000000..80ddf1c948 --- /dev/null +++ b/components/esp32c3/include/esp32c3/brownout.h @@ -0,0 +1,21 @@ +// Copyright 2015-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. + + +#ifndef __ESP_BROWNOUT_H +#define __ESP_BROWNOUT_H + +void esp_brownout_init(void); + +#endif diff --git a/components/esp32c3/include/esp32c3/cache_err_int.h b/components/esp32c3/include/esp32c3/cache_err_int.h new file mode 100644 index 0000000000..9c8d9ddb2f --- /dev/null +++ b/components/esp32c3/include/esp32c3/cache_err_int.h @@ -0,0 +1,33 @@ +// Copyright 2015-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. + + +/** + * @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 + * from the startup code. + */ +void esp_cache_err_int_init(void); + + +/** + * @brief get the CPU which caused cache invalid access interrupt + * @return + * - PRO_CPU_NUM, if PRO_CPU has caused cache IA interrupt + * - APP_CPU_NUM, if APP_CPU has caused cache IA interrupt + * - (-1) otherwise + */ +int esp_cache_err_get_cpuid(void); diff --git a/components/esp32c3/include/esp32c3/clk.h b/components/esp32c3/include/esp32c3/clk.h new file mode 100644 index 0000000000..1d4e462bcc --- /dev/null +++ b/components/esp32c3/include/esp32c3/clk.h @@ -0,0 +1,84 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file esp_clk.h + * + * This file contains declarations of clock related functions. + */ + +/** + * @brief Get the calibration value of RTC slow clock + * + * The value is in the same format as returned by rtc_clk_cal (microseconds, + * in Q13.19 fixed-point format). + * + * @return the calibration value obtained using rtc_clk_cal, at startup time + */ +uint32_t esp_clk_slowclk_cal_get(void); + +/** + * @brief Update the calibration value of RTC slow clock + * + * The value has to be in the same format as returned by rtc_clk_cal (microseconds, + * in Q13.19 fixed-point format). + * This value is used by timekeeping functions (such as gettimeofday) to + * calculate current time based on RTC counter value. + * @param value calibration value obtained using rtc_clk_cal + */ +void esp_clk_slowclk_cal_set(uint32_t value); + +/** + * @brief Return current CPU clock frequency + * When frequency switching is performed, this frequency may change. + * However it is guaranteed that the frequency never changes with a critical + * section. + * + * @return CPU clock frequency, in Hz + */ +int esp_clk_cpu_freq(void); + +/** + * @brief Return current APB clock frequency + * + * When frequency switching is performed, this frequency may change. + * However it is guaranteed that the frequency never changes with a critical + * section. + * + * @return APB clock frequency, in Hz + */ +int esp_clk_apb_freq(void); + + +/** + * @brief Read value of RTC counter, converting it to microseconds + * @attention The value returned by this function may change abruptly when + * calibration value of RTC counter is updated via esp_clk_slowclk_cal_set + * function. This should not happen unless application calls esp_clk_slowclk_cal_set. + * In ESP-IDF, esp_clk_slowclk_cal_set is only called in startup code. + * + * @return Value or RTC counter, expressed in microseconds + */ +uint64_t esp_clk_rtc_time(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp32c3/include/esp32c3/dport_access.h b/components/esp32c3/include/esp32c3/dport_access.h new file mode 100644 index 0000000000..f3f7007a9c --- /dev/null +++ b/components/esp32c3/include/esp32c3/dport_access.h @@ -0,0 +1,42 @@ +// Copyright 2010-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. + +#ifndef _ESP_DPORT_ACCESS_H_ +#define _ESP_DPORT_ACCESS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Read a sequence of DPORT registers to the buffer. + * + * @param[out] buff_out Contains the read data. + * @param[in] address Initial address for reading registers. + * @param[in] num_words The number of words. + */ +void esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address, uint32_t num_words); + +#define DPORT_STALL_OTHER_CPU_START() +#define DPORT_STALL_OTHER_CPU_END() +#define DPORT_INTERRUPT_DISABLE() +#define DPORT_INTERRUPT_RESTORE() + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_DPORT_ACCESS_H_ */ diff --git a/components/esp32c3/include/esp32c3/memprot.h b/components/esp32c3/include/esp32c3/memprot.h new file mode 100644 index 0000000000..ad42b3abbd --- /dev/null +++ b/components/esp32c3/include/esp32c3/memprot.h @@ -0,0 +1,356 @@ +// 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 + +#include +#include "esp_attr.h" + +#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 diff --git a/components/esp32c3/include/esp32c3/rtc.h b/components/esp32c3/include/esp32c3/rtc.h new file mode 100644 index 0000000000..b090ae5cfb --- /dev/null +++ b/components/esp32c3/include/esp32c3/rtc.h @@ -0,0 +1,40 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file esp32c3/rtc.h + * + * This file contains declarations of rtc related functions. + */ + +/** + * @brief Get current value of RTC counter in microseconds + * + * Note: this function may take up to 1 RTC_SLOW_CLK cycle to execute + * + * @return current value of RTC counter in microseconds + */ +uint64_t esp_rtc_get_time_us(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp32c3/include/esp_clk.h b/components/esp32c3/include/esp_clk.h new file mode 100644 index 0000000000..78f6678aac --- /dev/null +++ b/components/esp32c3/include/esp_clk.h @@ -0,0 +1,77 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +/** + * @file esp_clk.h + * + * This file contains declarations of clock related functions. + */ + +/** + * @brief Get the calibration value of RTC slow clock + * + * The value is in the same format as returned by rtc_clk_cal (microseconds, + * in Q13.19 fixed-point format). + * + * @return the calibration value obtained using rtc_clk_cal, at startup time + */ +uint32_t esp_clk_slowclk_cal_get(void); + +/** + * @brief Update the calibration value of RTC slow clock + * + * The value has to be in the same format as returned by rtc_clk_cal (microseconds, + * in Q13.19 fixed-point format). + * This value is used by timekeeping functions (such as gettimeofday) to + * calculate current time based on RTC counter value. + * @param value calibration value obtained using rtc_clk_cal + */ +void esp_clk_slowclk_cal_set(uint32_t value); + +/** + * @brief Return current CPU clock frequency + * When frequency switching is performed, this frequency may change. + * However it is guaranteed that the frequency never changes with a critical + * section. + * + * @return CPU clock frequency, in Hz + */ +int esp_clk_cpu_freq(void); + +/** + * @brief Return current APB clock frequency + * + * When frequency switching is performed, this frequency may change. + * However it is guaranteed that the frequency never changes with a critical + * section. + * + * @return APB clock frequency, in Hz + */ +int esp_clk_apb_freq(void); + + +/** + * @brief Read value of RTC counter, converting it to microseconds + * @attention The value returned by this function may change abruptly when + * calibration value of RTC counter is updated via esp_clk_slowclk_cal_set + * function. This should not happen unless application calls esp_clk_slowclk_cal_set. + * In ESP-IDF, esp_clk_slowclk_cal_set is only called in startup code. + * + * @return Value or RTC counter, expressed in microseconds + */ +uint64_t esp_clk_rtc_time(void); diff --git a/components/esp32c3/include/esp_crypto_lock.h b/components/esp32c3/include/esp_crypto_lock.h new file mode 100644 index 0000000000..cd0e7e3203 --- /dev/null +++ b/components/esp32c3/include/esp_crypto_lock.h @@ -0,0 +1,87 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Acquire lock for HMAC cryptography peripheral + * + * Internally also locks the SHA peripheral, as the HMAC depends on the SHA peripheral + */ +void esp_crypto_hmac_lock_acquire(void); + +/** + * @brief Release lock for HMAC cryptography peripheral + * + * Internally also releases the SHA peripheral, as the HMAC depends on the SHA peripheral + */ +void esp_crypto_hmac_lock_release(void); + +/** + * @brief Acquire lock for DS cryptography peripheral + * + * Internally also locks the HMAC (which locks SHA), AES and MPI peripheral, as the DS depends on these peripherals + */ +void esp_crypto_ds_lock_acquire(void); + +/** + * @brief Release lock for DS cryptography peripheral + * + * Internally also releases the HMAC (which locks SHA), AES and MPI peripheral, as the DS depends on these peripherals + */ +void esp_crypto_ds_lock_release(void); + +/** + * @brief Acquire lock for the SHA cryptography peripheral. + * + */ +void esp_crypto_sha_lock_acquire(void); + +/** + * @brief Release lock for the SHA cryptography peripheral. + * + */ +void esp_crypto_sha_lock_release(void); + +/** + * @brief Acquire lock for the aes cryptography peripheral. + * + */ +void esp_crypto_aes_lock_acquire(void); + +/** + * @brief Release lock for the aes cryptography peripheral. + * + */ +void esp_crypto_aes_lock_release(void); + +/** + * @brief Acquire lock for the mpi cryptography peripheral. + * + */ +void esp_crypto_mpi_lock_acquire(void); + +/** + * @brief Release lock for the mpi/rsa cryptography peripheral. + * + */ +void esp_crypto_mpi_lock_release(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp32c3/include/esp_hmac.h b/components/esp32c3/include/esp_hmac.h new file mode 100644 index 0000000000..391ba12fe1 --- /dev/null +++ b/components/esp32c3/include/esp_hmac.h @@ -0,0 +1,67 @@ +// Copyright 2015-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. + +#ifndef _ESP_HMAC_H_ +#define _ESP_HMAC_H_ + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The possible efuse keys for the HMAC peripheral + */ +typedef enum { + HMAC_KEY0 = 0, + HMAC_KEY1, + HMAC_KEY2, + HMAC_KEY3, + HMAC_KEY4, + HMAC_KEY5, + HMAC_KEY_MAX +} hmac_key_id_t; + +/** + * @brief + * Calculate the HMAC of a given message. + * + * Calculate the HMAC \c hmac of a given message \c message with length \c message_len. + * SHA256 is used for the calculation (fixed on ESP32S2). + * + * @note Uses the HMAC peripheral in "upstream" mode. + * + * @param key_id Determines which of the 6 key blocks in the efuses should be used for the HMAC calcuation. + * The corresponding purpose field of the key block in the efuse must be set to the HMAC upstream purpose value. + * @param message the message for which to calculate the HMAC + * @param message_len message length + * return ESP_ERR_INVALID_STATE if unsuccessful + * @param [out] hmac the hmac result; the buffer behind the provided pointer must be 32 bytes long + * + * @return + * * ESP_OK, if the calculation was successful, + * * ESP_FAIL, if the hmac calculation failed + */ +esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, + const void *message, + size_t message_len, + uint8_t *hmac); + +#ifdef __cplusplus +} +#endif + +#endif // _ESP_HMAC_H_ diff --git a/components/esp32c3/ld/esp32c3.ld b/components/esp32c3/ld/esp32c3.ld new file mode 100644 index 0000000000..cbf54bc2b0 --- /dev/null +++ b/components/esp32c3/ld/esp32c3.ld @@ -0,0 +1,101 @@ +/** + * ESP32-C3 Linker Script Memory Layout + * This file describes the memory layout (memory blocks) by virtual memory addresses. + * This linker script is passed through the C preprocessor to include configuration options. + * Please use preprocessor features sparingly! + * Restrict to simple macros with numeric values, and/or #if/#endif blocks. + */ + +#include "sdkconfig.h" + +#define SRAM_IRAM_START 0x4037C000 +#define SRAM_DRAM_START 0x3FC7C000 +#define ICACHE_SIZE 0x4000 /* ICache size is fixed to 16KB on ESP32-C3 */ +#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START) +#define SRAM_DRAM_END 0x403D0000 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */ + +#define SRAM_IRAM_ORG (SRAM_IRAM_START + ICACHE_SIZE) +#define SRAM_DRAM_ORG (SRAM_DRAM_START + ICACHE_SIZE) + +#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG + +#if CONFIG_ESP32C3_USE_FIXED_STATIC_RAM_SIZE +ASSERT((CONFIG_ESP32C3_FIXED_STATIC_RAM_SIZE <= I_D_SRAM_SIZE), "Fixed static ram data does not fit.") +#define DRAM0_0_SEG_LEN CONFIG_ESP3C3_FIXED_STATIC_RAM_SIZE +#else +#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE +#endif // CONFIG_ESP32C3_USE_FIXED_STATIC_RAM_SIZE +MEMORY +{ + /** + * All these values assume the flash cache is on, and have the blocks this uses subtracted from the length + * of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but + * are connected to the data port of the CPU and eg allow byte-wise access. + */ + + /* IRAM for PRO CPU. */ + iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + /* Flash mapped instruction data */ + iram0_2_seg (RX) : org = 0x42000020, len = 0x8000000-0x20 + + /** + * (0x20 offset above is a convenience for the app binary image generation. + * Flash cache has 64KB pages. The .bin file which is flashed to the chip + * has a 0x18 byte file header, and each segment has a 0x08 byte segment + * header. Setting this offset makes it simple to meet the flash cache MMU's + * constraint that (paddr % 64KB == vaddr % 64KB).) + */ +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + + /** + * Shared data RAM, excluding memory reserved for ROM bss/data/stack. + * Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available. + */ + dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + /* Flash mapped constant data */ + drom0_0_seg (R) : org = 0x3C000020, len = 0x8000000-0x20 + + /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + + /** + * RTC fast memory (executable). Persists over deep sleep. + */ + rtc_iram_seg(RWX) : org = 0x50000000, len = 0x2000 +} + +#if CONFIG_ESP32C3_USE_FIXED_STATIC_RAM_SIZE +/* static data ends at defined address */ +_static_data_end = 0x3FCA0000 + DRAM0_0_SEG_LEN; +#else +_static_data_end = _bss_end; +#endif // CONFIG_ESP32C3_USE_FIXED_STATIC_RAM_SIZE + +/* Heap ends at top of dram0_0_seg */ +_heap_end = 0x40000000; + +_data_seg_org = ORIGIN(rtc_data_seg); + +/** + * The lines below define location alias for .rtc.data section + * As C3 only has RTC fast memory, this is not configurable like on other targets + */ +REGION_ALIAS("rtc_data_seg", rtc_iram_seg ); +REGION_ALIAS("rtc_slow_seg", rtc_iram_seg ); +REGION_ALIAS("rtc_data_location", rtc_iram_seg ); + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + REGION_ALIAS("default_code_seg", iram0_2_seg); +#else + REGION_ALIAS("default_code_seg", iram0_0_seg); +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + REGION_ALIAS("default_rodata_seg", drom0_0_seg); +#else + REGION_ALIAS("default_rodata_seg", dram0_0_seg); +#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS diff --git a/components/esp32c3/ld/esp32c3.peripherals.ld b/components/esp32c3/ld/esp32c3.peripherals.ld new file mode 100644 index 0000000000..728d1b7199 --- /dev/null +++ b/components/esp32c3/ld/esp32c3.peripherals.ld @@ -0,0 +1,29 @@ +PROVIDE ( UART0 = 0x60000000 ); +PROVIDE ( UART1 = 0x60010000 ); +PROVIDE ( UART2 = 0x6002e000 ); +PROVIDE ( SPIMEM1 = 0x60002000 ); +PROVIDE ( SPIMEM0 = 0x60003000 ); +PROVIDE ( GPIO = 0x60004000 ); +PROVIDE ( SIGMADELTA = 0x60004f00 ); +PROVIDE ( RTCCNTL = 0x60008000 ); +PROVIDE ( RTCIO = 0x60008400 ); +PROVIDE ( SENS = 0x60008800 ); +PROVIDE ( HINF = 0x6000B000 ); +PROVIDE ( I2S1 = 0x6002d000 ); +PROVIDE ( I2C0 = 0x60013000 ); +PROVIDE ( UHCI0 = 0x60014000 ); +PROVIDE ( UHCI1 = 0x6000c000 ); +PROVIDE ( HOST = 0x60015000 ); +PROVIDE ( RMT = 0x60016000 ); +PROVIDE ( RMTMEM = 0x60016400 ); +PROVIDE ( PCNT = 0x60017000 ); +PROVIDE ( SLC = 0x60018000 ); +PROVIDE ( LEDC = 0x60019000 ); +PROVIDE ( TIMERG0 = 0x6001F000 ); +PROVIDE ( TIMERG1 = 0x60020000 ); +PROVIDE ( GPSPI2 = 0x60024000 ); +PROVIDE ( GPSPI3 = 0x60025000 ); +PROVIDE ( SYSCON = 0x60026000 ); +PROVIDE ( GPSPI4 = 0x60037000 ); +PROVIDE ( APB_SARADC = 0x60040000 ); +PROVIDE ( GDMA = 0x6003F000 ); diff --git a/components/esp32c3/ld/esp32c3.project.ld.in b/components/esp32c3/ld/esp32c3.project.ld.in new file mode 100644 index 0000000000..687f5128ec --- /dev/null +++ b/components/esp32c3/ld/esp32c3.project.ld.in @@ -0,0 +1,395 @@ +/* Default entry point */ +ENTRY(call_start_cpu0); + +SECTIONS +{ + /** + * RTC fast memory holds RTC wake stub code, + * including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + + mapping[rtc_text] + + *rtc_wake_stub*.*(.literal .text .literal.* .text.*) + _rtc_text_end = ABSOLUTE(.); + } > rtc_iram_seg + + /** + * This section is required to skip rtc.text area because rtc_iram_seg and + * rtc_data_seg are reflect the same address space on different buses. + */ + .rtc.dummy : + { + _rtc_dummy_start = ABSOLUTE(.); + _rtc_fast_start = ABSOLUTE(.); + . = SIZEOF(.rtc.text); + _rtc_dummy_end = ABSOLUTE(.); + } > rtc_data_seg + + /** + * This section located in RTC FAST Memory area. + * It holds data marked with RTC_FAST_ATTR attribute. + * See the file "esp_attr.h" for more information. + */ + .rtc.force_fast : + { + . = ALIGN(4); + _rtc_force_fast_start = ABSOLUTE(.); + + _coredump_rtc_fast_start = ABSOLUTE(.); + mapping[rtc_fast_coredump] + _coredump_rtc_fast_end = ABSOLUTE(.); + + *(.rtc.force_fast .rtc.force_fast.*) + . = ALIGN(4) ; + _rtc_force_fast_end = ABSOLUTE(.); + } > rtc_data_seg + + /** + * RTC data section holds RTC wake stub + * data/rodata, including from any source file + * named rtc_wake_stub*.c and the data marked with + * RTC_DATA_ATTR, RTC_RODATA_ATTR attributes. + * The memory location of the data is dependent on + * CONFIG_ESP32C3_RTCDATA_IN_FAST_MEM option. + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + + /* coredump mapping */ + _coredump_rtc_start = ABSOLUTE(.); + mapping[rtc_coredump] + _coredump_rtc_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ + mapping[rtc_data] + + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) + _rtc_data_end = ABSOLUTE(.); + } > rtc_data_location + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.*(.bss .bss.*) + *rtc_wake_stub*.*(COMMON) + + mapping[rtc_bss] + + _rtc_bss_end = ABSOLUTE(.); + } > rtc_data_location + + /** + * This section holds data that should not be initialized at power up + * and will be retained during deep sleep. + * User data marked with RTC_NOINIT_ATTR will be placed + * into this section. See the file "esp_attr.h" for more information. + * The memory location of the data is dependent on CONFIG_ESP32C3_RTCDATA_IN_FAST_MEM option. + */ + .rtc_noinit (NOLOAD): + { + . = ALIGN(4); + _rtc_noinit_start = ABSOLUTE(.); + *(.rtc_noinit .rtc_noinit.*) + . = ALIGN(4) ; + _rtc_noinit_end = ABSOLUTE(.); + } > rtc_data_location + + /** + * This section located in RTC SLOW Memory area. + * It holds data marked with RTC_SLOW_ATTR attribute. + * See the file "esp_attr.h" for more information. + */ + .rtc.force_slow : + { + . = ALIGN(4); + _rtc_force_slow_start = ABSOLUTE(.); + *(.rtc.force_slow .rtc.force_slow.*) + . = ALIGN(4) ; + _rtc_force_slow_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* Get size of rtc slow data based on rtc_data_location alias */ + _rtc_slow_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) + ? (_rtc_force_slow_end - _rtc_data_start) + : (_rtc_force_slow_end - _rtc_force_slow_start); + + _rtc_fast_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) + ? (_rtc_force_fast_end - _rtc_fast_start) + : (_rtc_noinit_end - _rtc_fast_start); + + ASSERT((_rtc_slow_length <= LENGTH(rtc_slow_seg)), + "RTC_SLOW segment data does not fit.") + + ASSERT((_rtc_fast_length <= LENGTH(rtc_data_seg)), + "RTC_FAST segment data does not fit.") + + .iram0.text : + { + _iram_start = ABSOLUTE(.); + /* Vectors go to start of IRAM */ + ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned"); + KEEP(*(.exception_vectors.text)); + . = ALIGN(4); + + _invalid_pc_placeholder = ABSOLUTE(.); + + /* Code marked as running out of IRAM */ + _iram_text_start = ABSOLUTE(.); + + mapping[iram0_text] + + } > iram0_0_seg + + /** + * This section is required to skip .iram0.text area because iram0_0_seg and + * dram0_0_seg reflect the same address space on different buses. + */ + .dram0.dummy (NOLOAD): + { + . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start; + } > dram0_0_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + _bt_data_start = ABSOLUTE(.); + *libbt.a:(.data .data.*) + . = ALIGN (4); + _bt_data_end = ABSOLUTE(.); + _btdm_data_start = ABSOLUTE(.); + *libbtdm_app.a:(.data .data.*) + . = ALIGN (4); + _btdm_data_end = ABSOLUTE(.); + _nimble_data_start = ABSOLUTE(.); + *libnimble.a:(.data .data.*) + . = ALIGN (4); + _nimble_data_end = ABSOLUTE(.); + *(.gnu.linkonce.d.*) + *(.data1) + __global_pointer$ = . + 0x800; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + + /* coredump mapping */ + _coredump_dram_start = ABSOLUTE(.); + mapping[dram_coredump] + _coredump_dram_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ + _esp_system_init_fn_array_start = ABSOLUTE(.); + KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + + mapping[dram0_data] + + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } > dram0_0_seg + + /** + * This section holds data that should not be initialized at power up. + * The section located in Internal SRAM memory region. The macro _NOINIT + * can be used as attribute to place data into this section. + * See the "esp_attr.h" file for more information. + */ + .noinit (NOLOAD): + { + . = ALIGN(4); + _noinit_start = ABSOLUTE(.); + *(.noinit .noinit.*) + . = ALIGN(4) ; + _noinit_end = ABSOLUTE(.); + } > dram0_0_seg + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + _bt_bss_start = ABSOLUTE(.); + *libbt.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _bt_bss_end = ABSOLUTE(.); + _btdm_bss_start = ABSOLUTE(.); + *libbtdm_app.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _btdm_bss_end = ABSOLUTE(.); + _nimble_bss_start = ABSOLUTE(.); + *libnimble.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _nimble_bss_end = ABSOLUTE(.); + + mapping[dram0_bss] + + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.share.mem) + *(.gnu.linkonce.b.*) + + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } > dram0_0_seg + + ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.") + + .flash.text : + { + _stext = .; + _instruction_reserved_start = ABSOLUTE(.); + _text_start = ABSOLUTE(.); + + mapping[flash_text] + + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _instruction_reserved_end = ABSOLUTE(.); + _etext = .; + + /** + * Similar to _iram_start, this symbol goes here so it is + * resolved by addr2line in preference to the first symbol in + * the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); + } > default_code_seg + + .flash_rodata_dummy (NOLOAD): + { + . = SIZEOF(.flash.text); + . = ALIGN(0x10000) + 0x20; + _rodata_reserved_start = .; + } > drom0_0_seg + + /* When modifying the alignment, don't forget to update tls_section_alignment in pxPortInitialiseStack */ + .flash.rodata : ALIGN(0x10) + { + _rodata_start = ABSOLUTE(.); + + *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ + *(.rodata_custom_desc .rodata_custom_desc.*) /* Should be the second. Custom app version info. DO NOT PUT ANYTHING BEFORE IT! */ + + mapping[flash_rodata] + + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 3) & ~ 3; + __eh_frame = ABSOLUTE(.); + KEEP(*(.eh_frame)) + . = (. + 7) & ~ 3; + /* C++ constructor and destructor tables */ + /* Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt */ + __init_array_start = ABSOLUTE(.); + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array .ctors .ctors.*)) + __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.*(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + /* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */ + soc_reserved_memory_region_start = ABSOLUTE(.); + KEEP (*(.reserved_memory_address)) + soc_reserved_memory_region_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + *(.srodata) + *(.srodata.*) + _thread_local_end = ABSOLUTE(.); + _rodata_reserved_end = ABSOLUTE(.); + . = ALIGN(4); + } > default_rodata_seg + + /* Marks the end of IRAM code segment */ + .iram0.text_end (NOLOAD) : + { + . = ALIGN (16); + _iram_text_end = ABSOLUTE(.); + } > iram0_0_seg + + .iram0.data : + { + . = ALIGN(16); + _iram_data_start = ABSOLUTE(.); + + /* coredump mapping */ + _coredump_iram_start = ABSOLUTE(.); + mapping[iram_coredump] + _coredump_iram_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ + mapping[iram0_data] + + _iram_data_end = ABSOLUTE(.); + } > iram0_0_seg + + .iram0.bss (NOLOAD) : + { + . = ALIGN(16); + _iram_bss_start = ABSOLUTE(.); + + mapping[iram0_bss] + + _iram_bss_end = ABSOLUTE(.); + . = ALIGN(16); + _iram_end = ABSOLUTE(.); + } > iram0_0_seg + + /* Marks the end of data, bss and possibly rodata */ + .dram0.heap_start (NOLOAD) : + { + . = ALIGN (16); + _heap_start = ABSOLUTE(.); + } > dram0_0_seg +} + +ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), + "IRAM0 segment data does not fit.") + +ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), + "DRAM segment data does not fit.") diff --git a/components/esp32c3/ld/esp32c3_fragments.lf b/components/esp32c3/ld/esp32c3_fragments.lf new file mode 100644 index 0000000000..2ab27f1091 --- /dev/null +++ b/components/esp32c3/ld/esp32c3_fragments.lf @@ -0,0 +1,132 @@ +[sections:text] +entries: + .text+ + .literal+ + +[sections:data] +entries: + .data+ + +[sections:bss] +entries: + .bss+ + +[sections:common] +entries: + COMMON + +[sections:rodata] +entries: + .rodata+ + +[sections:rtc_text] +entries: + .rtc.text+ + .rtc.literal + +[sections:rtc_data] +entries: + .rtc.data+ + +[sections:rtc_rodata] +entries: + .rtc.rodata+ + +[sections:rtc_bss] +entries: + .rtc.bss + +[sections:rtc_fast_coredump] +entries: + .rtc.fast.coredump+ + +[sections:rtc_coredump] +entries: + .rtc.coredump+ + +[sections:dram_coredump] +entries: + .dram1.coredump+ + +[sections:iram_coredump] +entries: + .iram.data.coredump+ + +[sections:iram] +entries: + .iram1+ + +[sections:iram_data] +entries: + .iram.data+ + +[sections:iram_bss] +entries: + .iram.bss+ + +[sections:dram] +entries: + .dram1+ + +[sections:wifi_iram] +entries: + .wifi0iram+ + +[sections:wifi_rx_iram] +entries: + .wifirxiram+ + +[scheme:default] +entries: + if APP_BUILD_USE_FLASH_SECTIONS = y: + text -> flash_text + rodata -> flash_rodata + else: + text -> iram0_text + rodata -> dram0_data + data -> dram0_data + bss -> dram0_bss + common -> dram0_bss + iram -> iram0_text + iram_data -> iram0_data + iram_bss -> iram0_bss + dram -> dram0_data + rtc_text -> rtc_text + rtc_data -> rtc_data + rtc_rodata -> rtc_data + rtc_bss -> rtc_bss + wifi_iram -> flash_text + wifi_rx_iram -> flash_text + dram_coredump -> dram_coredump + iram_coredump -> iram_coredump + rtc_coredump -> rtc_coredump + rtc_fast_coredump -> rtc_fast_coredump + +[scheme:rtc] +entries: + text -> rtc_text + data -> rtc_data + rodata -> rtc_data + bss -> rtc_bss + common -> rtc_bss + +[scheme:noflash] +entries: + text -> iram0_text + rodata -> dram0_data + +[scheme:noflash_data] +entries: + rodata -> dram0_data + +[scheme:noflash_text] +entries: + text -> iram0_text + +[scheme:wifi_iram] +entries: + wifi_iram -> iram0_text + +[scheme:wifi_rx_iram] +entries: + wifi_rx_iram -> iram0_text diff --git a/components/esp32c3/linker.lf b/components/esp32c3/linker.lf new file mode 100644 index 0000000000..87e068ccd4 --- /dev/null +++ b/components/esp32c3/linker.lf @@ -0,0 +1,9 @@ +[mapping:gcc] +archive: libgcc.a +entries: + lib2funcs (noflash_text) + +[mapping:gcov] +archive: libgcov.a +entries: + * (noflash) diff --git a/components/esp32c3/project_include.cmake b/components/esp32c3/project_include.cmake new file mode 100644 index 0000000000..98d8425094 --- /dev/null +++ b/components/esp32c3/project_include.cmake @@ -0,0 +1,5 @@ +set(compile_options "-Wno-error=format=" + "-nostartfiles" + "-Wno-format") + +idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND) diff --git a/components/esp32c3/system_api_esp32c3.c b/components/esp32c3/system_api_esp32c3.c new file mode 100644 index 0000000000..fb8addf4ac --- /dev/null +++ b/components/esp32c3/system_api_esp32c3.c @@ -0,0 +1,141 @@ +// Copyright 2013-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. + +#include +#include "sdkconfig.h" +#include "esp_system.h" +#include "esp_private/system_internal.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp32c3/rom/cache.h" +#include "esp32c3/cache_err_int.h" +#include "riscv/riscv_interrupts.h" +#include "riscv/interrupt.h" +#include "esp_rom_uart.h" +#include "soc/gpio_reg.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/timer_group_reg.h" +#include "soc/cpu.h" +#include "soc/rtc.h" +#include "soc/syscon_reg.h" +#include "soc/system_reg.h" +#include "hal/wdt_hal.h" + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void IRAM_ATTR esp_restart_noos(void) +{ + // Disable interrupts + riscv_global_interrupts_disable(); + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + + // Reset and stall the other CPU. + // CPU must be reset before stalling, in case it was running a s32c1i + // instruction. This would cause memory pool to be locked by arbiter + // to the stalled CPU, preventing current CPU from accessing this pool. + const uint32_t core_id = cpu_hal_get_core_id(); +#if !CONFIG_FREERTOS_UNICORE + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + esp_cpu_reset(other_core_id); + esp_cpu_stall(other_core_id); +#endif + + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + + // Flush any data left in UART FIFOs + esp_rom_uart_tx_wait_idle(0); + esp_rom_uart_tx_wait_idle(1); + // Disable cache + Cache_Disable_ICache(); + + // 2nd stage bootloader reconfigures SPI flash signals. + // Reset them to the defaults expected by ROM. + WRITE_PERI_REG(GPIO_FUNC0_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC1_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC2_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC3_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC4_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); + + // Reset wifi/bluetooth/ethernet/sdio (bb/mac) + SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, + SYSTEM_BB_RST | SYSTEM_FE_RST | SYSTEM_MAC_RST | + SYSTEM_BT_RST | SYSTEM_BTMAC_RST | SYSTEM_MACPWR_RST | + SYSTEM_RW_BTMAC_RST | SYSTEM_RW_BTLP_RST); + REG_WRITE(SYSTEM_CORE_RST_EN_REG, 0); + + // Reset timer/spi/uart + SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG, + SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST); + REG_WRITE(SYSTEM_PERIP_RST_EN0_REG, 0); + REG_WRITE(SYSTEM_PERIP_RST_EN1_REG, 0); + // Set CPU back to XTAL source, no PLL, same as hard reset +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_freq_set_xtal(); +#endif + +#if !CONFIG_FREERTOS_UNICORE + // Clear entry point for APP CPU + REG_WRITE(SYSTEM_CORE_1_CONTROL_1_REG, 0); +#endif + + // Reset CPUs + if (core_id == 0) { + // Running on PRO CPU: APP CPU is stalled. Can reset both CPUs. +#if !CONFIG_FREERTOS_UNICORE + esp_cpu_reset(1); +#endif + esp_cpu_reset(0); + } +#if !CONFIG_FREERTOS_UNICORE + else { + // Running on APP CPU: need to reset PRO CPU and unstall it, + // then reset APP CPU + esp_cpu_reset(0); + esp_cpu_unstall(0); + esp_cpu_reset(1); + } +#endif + while (true) { + ; + } +} + +void esp_chip_info(esp_chip_info_t *out_info) +{ + memset(out_info, 0, sizeof(*out_info)); + out_info->model = CHIP_ESP32C3; + out_info->cores = 1; + out_info->features = CHIP_FEATURE_WIFI_BGN | CHIP_FEATURE_BLE; +}