From 65aebef596418fca6d15a091ab2bf9924d4f6130 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Dec 2020 16:37:16 +0800 Subject: [PATCH 1/4] esp32c3: added 2nd bootloader project linker file --- .../subproject/main/ld/esp32c3/bootloader.ld | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 components/bootloader/subproject/main/ld/esp32c3/bootloader.ld diff --git a/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld new file mode 100644 index 0000000000..8af0e142c6 --- /dev/null +++ b/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld @@ -0,0 +1,182 @@ +/** Simplified memory map for the bootloader. + * Make sure the bootloader can load into main memory without overwriting itself. + * We put 2nd bootloader in the high address space (before ROM stack/data/bss). + * See memory usage for ROM bootloader at the end of this file. + */ + +MEMORY +{ + iram_seg (RWX) : org = 0x403CE000, len = 0x2000 + iram_loader_seg (RWX) : org = 0x403D0000, len = 0x6000 + dram_seg (RW) : org = 0x3FCD6000, len = 0x4000 +} + +/* Default entry point: */ +ENTRY(call_start_cpu0); + +SECTIONS +{ + + .iram_loader.text : + { + . = ALIGN (16); + _loader_text_start = ABSOLUTE(.); + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.iram1 .iram1.*) /* catch stray IRAM_ATTR */ + *liblog.a:(.literal .text .literal.* .text.*) + *libgcc.a:(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_disable .text.bootloader_random_disable) + *libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_enable .text.bootloader_random_enable) + *libbootloader_support.a:bootloader_efuse_esp32c3.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*) + *libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*) + *libmicro-ecc.a:*.*(.literal .text .literal.* .text.*) + *libspi_flash.a:*.*(.literal .text .literal.* .text.*) + *libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*) + *libesp_hw_support.a:rtc_clk.*(.literal .text .literal.* .text.*) + *libesp_hw_support.a:rtc_time.*(.literal .text .literal.* .text.*) + *libesp_hw_support.a:regi2c_ctrl.*(.literal .text .literal.* .text.*) + *libefuse.a:*.*(.literal .text .literal.* .text.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _loader_text_end = ABSOLUTE(.); + } > iram_loader_seg + + .iram.text : + { + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + } > iram_seg + + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _dram_start = ABSOLUTE(.); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } > dram_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } > dram_seg + + .dram0.rodata : + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + . = (. + 3) & ~ 3; + /* C++ constructor and destructor tables, properly ordered: */ + __init_array_start = ABSOLUTE(.); + KEEP (*crtbegin.*(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.*) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.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) + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _dram_end = ABSOLUTE(.); + } > dram_seg + + .iram.text : + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.iram .iram.*) /* catch stray IRAM_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } > iram_seg + +} + + +/** + * Appendix: Memory Usage of ROM bootloader + * + * +--------+--------------+------+ 0x3FCC_B000 + * | ^ | + * | | | + * | | data/bss | + * | | | + * | v | + * +------------------------------+ 0x3FCD_C910 + * | ^ | + * | | | + * | | stack | + * | | | + * | v | + * +------------------------------+ 0x3FCD_E910 + */ From 8330b2541a0019989992b5e7d379da11d9feca1c Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Dec 2020 20:03:10 +0800 Subject: [PATCH 2/4] esp32c3: added target component --- components/esp32c3/CMakeLists.txt | 71 ++++ components/esp32c3/Kconfig | 219 ++++++++++ components/esp32c3/Makefile.projbuild | 1 + components/esp32c3/cache_err_int.c | 34 ++ components/esp32c3/clk.c | 38 ++ components/esp32c3/component.mk | 4 + components/esp32c3/crosscore_int.c | 97 +++++ components/esp32c3/dport_access.c | 25 ++ components/esp32c3/esp_crypto_lock.c | 98 +++++ components/esp32c3/esp_hmac.c | 132 ++++++ components/esp32c3/hw_random.c | 68 +++ components/esp32c3/include/esp32c3/brownout.h | 21 + .../esp32c3/include/esp32c3/cache_err_int.h | 33 ++ components/esp32c3/include/esp32c3/clk.h | 84 ++++ .../esp32c3/include/esp32c3/dport_access.h | 42 ++ components/esp32c3/include/esp32c3/memprot.h | 356 ++++++++++++++++ components/esp32c3/include/esp32c3/rtc.h | 40 ++ components/esp32c3/include/esp_clk.h | 77 ++++ components/esp32c3/include/esp_crypto_lock.h | 87 ++++ components/esp32c3/include/esp_hmac.h | 67 +++ components/esp32c3/ld/esp32c3.ld | 101 +++++ components/esp32c3/ld/esp32c3.peripherals.ld | 29 ++ components/esp32c3/ld/esp32c3.project.ld.in | 395 ++++++++++++++++++ components/esp32c3/ld/esp32c3_fragments.lf | 132 ++++++ components/esp32c3/linker.lf | 9 + components/esp32c3/project_include.cmake | 5 + components/esp32c3/system_api_esp32c3.c | 141 +++++++ 27 files changed, 2406 insertions(+) create mode 100644 components/esp32c3/CMakeLists.txt create mode 100644 components/esp32c3/Kconfig create mode 100644 components/esp32c3/Makefile.projbuild create mode 100644 components/esp32c3/cache_err_int.c create mode 100644 components/esp32c3/clk.c create mode 100644 components/esp32c3/component.mk create mode 100644 components/esp32c3/crosscore_int.c create mode 100644 components/esp32c3/dport_access.c create mode 100644 components/esp32c3/esp_crypto_lock.c create mode 100644 components/esp32c3/esp_hmac.c create mode 100644 components/esp32c3/hw_random.c create mode 100644 components/esp32c3/include/esp32c3/brownout.h create mode 100644 components/esp32c3/include/esp32c3/cache_err_int.h create mode 100644 components/esp32c3/include/esp32c3/clk.h create mode 100644 components/esp32c3/include/esp32c3/dport_access.h create mode 100644 components/esp32c3/include/esp32c3/memprot.h create mode 100644 components/esp32c3/include/esp32c3/rtc.h create mode 100644 components/esp32c3/include/esp_clk.h create mode 100644 components/esp32c3/include/esp_crypto_lock.h create mode 100644 components/esp32c3/include/esp_hmac.h create mode 100644 components/esp32c3/ld/esp32c3.ld create mode 100644 components/esp32c3/ld/esp32c3.peripherals.ld create mode 100644 components/esp32c3/ld/esp32c3.project.ld.in create mode 100644 components/esp32c3/ld/esp32c3_fragments.lf create mode 100644 components/esp32c3/linker.lf create mode 100644 components/esp32c3/project_include.cmake create mode 100644 components/esp32c3/system_api_esp32c3.c 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; +} From 3f287800eb99867c17022608fbf29bbf40843cd4 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Dec 2020 21:34:53 +0800 Subject: [PATCH 3/4] bootloader_support: added esp32-c3 support --- components/bootloader_support/component.mk | 5 +- .../src/bootloader_console.c | 6 +- .../src/bootloader_efuse_esp32c3.c | 28 ++ .../bootloader_support/src/bootloader_flash.c | 7 +- .../src/bootloader_flash_config_esp32c3.c | 83 +++++ .../src/bootloader_random_esp32c3.c | 31 ++ .../src/esp32c3/bootloader_esp32c3.c | 313 ++++++++++++++++++ .../src/esp32c3/bootloader_sha.c | 48 +++ .../src/esp32c3/flash_encrypt.c | 296 +++++++++++++++++ .../src/esp32c3/secure_boot.c | 45 +++ .../src/esp32c3/secure_boot_signatures.c | 93 ++++++ .../bootloader_support/src/esp_image_format.c | 5 + .../test/test_verify_image.c | 1 - 13 files changed, 952 insertions(+), 9 deletions(-) create mode 100644 components/bootloader_support/src/bootloader_efuse_esp32c3.c create mode 100644 components/bootloader_support/src/bootloader_flash_config_esp32c3.c create mode 100644 components/bootloader_support/src/bootloader_random_esp32c3.c create mode 100644 components/bootloader_support/src/esp32c3/bootloader_esp32c3.c create mode 100644 components/bootloader_support/src/esp32c3/bootloader_sha.c create mode 100644 components/bootloader_support/src/esp32c3/flash_encrypt.c create mode 100644 components/bootloader_support/src/esp32c3/secure_boot.c create mode 100644 components/bootloader_support/src/esp32c3/secure_boot_signatures.c diff --git a/components/bootloader_support/component.mk b/components/bootloader_support/component.mk index b24336fef1..26b2a59b8b 100644 --- a/components/bootloader_support/component.mk +++ b/components/bootloader_support/component.mk @@ -25,10 +25,13 @@ endif COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \ src/bootloader_flash_config_esp32s3.o \ + src/bootloader_flash_config_esp32c3.o \ src/bootloader_efuse_esp32s2.o \ src/bootloader_efuse_esp32s3.o \ + src/bootloader_efuse_esp32c3.o \ src/bootloader_random_esp32s2.o \ - src/bootloader_random_esp32s3.o + src/bootloader_random_esp32s3.o \ + src/bootloader_random_esp32c3.o ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME diff --git a/components/bootloader_support/src/bootloader_console.c b/components/bootloader_support/src/bootloader_console.c index b6730cebdc..7d80957648 100644 --- a/components/bootloader_support/src/bootloader_console.c +++ b/components/bootloader_support/src/bootloader_console.c @@ -42,7 +42,7 @@ void bootloader_console_init(void) { const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM; - esp_rom_install_channel_putc(1, esp_rom_uart_putc); + esp_rom_install_uart_printf(); // Wait for UART FIFO to be empty. esp_rom_uart_tx_wait_idle(0); @@ -52,7 +52,9 @@ void bootloader_console_init(void) const int uart_tx_gpio = CONFIG_ESP_CONSOLE_UART_TX_GPIO; const int uart_rx_gpio = CONFIG_ESP_CONSOLE_UART_RX_GPIO; // Switch to the new UART (this just changes UART number used for esp_rom_printf in ROM code). +#if ESP_ROM_SUPPORT_MULTIPLE_UART esp_rom_uart_set_as_console(uart_num); +#endif // If console is attached to UART1 or if non-default pins are used, // need to reconfigure pins using GPIO matrix if (uart_num != 0 || @@ -75,7 +77,7 @@ void bootloader_console_init(void) // Set configured UART console baud rate uint32_t clock_hz = rtc_clk_apb_freq_get(); -#if CONFIG_IDF_TARGET_ESP32S3 +#if ESP_ROM_UART_CLK_IS_XTAL clock_hz = UART_CLK_FREQ_ROM; // From esp32-s3 on, UART clock source is selected to XTAL in ROM #endif esp_rom_uart_set_clock_baudrate(uart_num, clock_hz, CONFIG_ESP_CONSOLE_UART_BAUDRATE); diff --git a/components/bootloader_support/src/bootloader_efuse_esp32c3.c b/components/bootloader_support/src/bootloader_efuse_esp32c3.c new file mode 100644 index 0000000000..196825a007 --- /dev/null +++ b/components/bootloader_support/src/bootloader_efuse_esp32c3.c @@ -0,0 +1,28 @@ +// 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 + +uint8_t bootloader_common_get_chip_revision(void) +{ + // should return the same value as esp_efuse_get_chip_ver() + /* No other revisions for ESP32-C3 */ + return 0; +} + +uint32_t bootloader_common_get_chip_ver_pkg(void) +{ + // should return the same value as esp_efuse_get_pkg_ver() + return 0; +} diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 905945309e..7a7d0ba4b7 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -404,12 +404,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool } if (write_encrypted) { -#if CONFIG_IDF_TARGET_ESP32 return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size)); -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - // TODO: use the same ROM API here - return spi_to_esp_err(SPI_Encrypt_Write(dest_addr, src, size)); -#endif } else { return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size)); } @@ -447,7 +442,9 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size) #endif +#ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here extern uint8_t g_rom_spiflash_dummy_len_plus[]; +#endif uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len) { uint32_t old_ctrl_reg = SPIFLASH.ctrl.val; diff --git a/components/bootloader_support/src/bootloader_flash_config_esp32c3.c b/components/bootloader_support/src/bootloader_flash_config_esp32c3.c new file mode 100644 index 0000000000..d140fa0ff6 --- /dev/null +++ b/components/bootloader_support/src/bootloader_flash_config_esp32c3.c @@ -0,0 +1,83 @@ +// 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 "string.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp32c3/rom/gpio.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/efuse.h" +#include "soc/gpio_periph.h" +#include "soc/efuse_reg.h" +#include "soc/spi_reg.h" +#include "soc/spi_mem_reg.h" +#include "soc/spi_caps.h" +#include "flash_qio_mode.h" +#include "bootloader_flash_config.h" +#include "bootloader_common.h" + +#define FLASH_IO_MATRIX_DUMMY_40M 0 +#define FLASH_IO_MATRIX_DUMMY_80M 0 + +void bootloader_flash_update_id() +{ + esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip; + chip->device_id = bootloader_read_flash_id(); +} + +void IRAM_ATTR bootloader_flash_cs_timing_config() +{ + SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); + SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); +} + +void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr) +{ + uint32_t spi_clk_div = 0; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + spi_clk_div = 1; + break; + case ESP_IMAGE_SPI_SPEED_40M: + spi_clk_div = 2; + break; + case ESP_IMAGE_SPI_SPEED_26M: + spi_clk_div = 3; + break; + case ESP_IMAGE_SPI_SPEED_20M: + spi_clk_div = 4; + break; + default: + break; + } + esp_rom_spiflash_config_clk(spi_clk_div, 0); +} + +void IRAM_ATTR bootloader_flash_set_dummy_out(void) +{ + REG_SET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL); + REG_SET_BIT(SPI_MEM_CTRL_REG(1), SPI_MEM_FDUMMY_OUT | SPI_MEM_D_POL | SPI_MEM_Q_POL); +} + +void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t *pfhdr) +{ + bootloader_configure_spi_pins(1); + bootloader_flash_set_dummy_out(); +} diff --git a/components/bootloader_support/src/bootloader_random_esp32c3.c b/components/bootloader_support/src/bootloader_random_esp32c3.c new file mode 100644 index 0000000000..4ab2e38981 --- /dev/null +++ b/components/bootloader_support/src/bootloader_random_esp32c3.c @@ -0,0 +1,31 @@ +// 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 "sdkconfig.h" +#include "bootloader_random.h" +#include "esp_log.h" + +static const char *TAG = "bootloader_random"; + +void bootloader_random_enable(void) +{ + ESP_LOGW(TAG, "RNG for ESP32-C3 not currently supported"); // IDF-2305 + // Don't forget to remove the following line + // *libbootloader_support.a:bootloader_random*.*(.literal.bootloader_random_enable .text.bootloader_random_enable) + // In the bootloader.ld when RNG support is ready for ESP32-C3 +} + +void bootloader_random_disable(void) +{ + ESP_LOGW(TAG, "RNG for ESP32-C3 not currently supported"); // IDF-2305 +} diff --git a/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c b/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c new file mode 100644 index 0000000000..0219da916b --- /dev/null +++ b/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c @@ -0,0 +1,313 @@ +// 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 "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "flash_qio_mode.h" +#include "esp_rom_gpio.h" +#include "esp_rom_efuse.h" +#include "esp_rom_uart.h" +#include "esp_rom_sys.h" +#include "soc/efuse_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/io_mux_reg.h" +#include "soc/assist_debug_reg.h" +#include "soc/cpu.h" +#include "soc/rtc.h" +#include "soc/spi_periph.h" +#include "soc/extmem_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/system_reg.h" +#include "esp32c3/rom/efuse.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/cache.h" +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/spi_flash.h" +#include "esp32c3/rom/rtc.h" +#include "bootloader_common.h" +#include "bootloader_init.h" +#include "bootloader_clock.h" +#include "bootloader_flash_config.h" +#include "bootloader_mem.h" +#include "regi2c_ctrl.h" +#include "bootloader_console.h" + +static const char *TAG = "boot.esp32c3"; + +void IRAM_ATTR bootloader_configure_spi_pins(int drv) +{ + const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info(); + uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio(); + uint8_t clk_gpio_num = SPI_CLK_GPIO_NUM; + uint8_t q_gpio_num = SPI_Q_GPIO_NUM; + uint8_t d_gpio_num = SPI_D_GPIO_NUM; + uint8_t cs0_gpio_num = SPI_CS0_GPIO_NUM; + uint8_t hd_gpio_num = SPI_HD_GPIO_NUM; + uint8_t wp_gpio_num = SPI_WP_GPIO_NUM; + if (spiconfig == 0) { + + } else { + clk_gpio_num = spiconfig & 0x3f; + q_gpio_num = (spiconfig >> 6) & 0x3f; + d_gpio_num = (spiconfig >> 12) & 0x3f; + cs0_gpio_num = (spiconfig >> 18) & 0x3f; + hd_gpio_num = (spiconfig >> 24) & 0x3f; + wp_gpio_num = wp_pin; + } + esp_rom_gpio_pad_set_drv(clk_gpio_num, drv); + esp_rom_gpio_pad_set_drv(q_gpio_num, drv); + esp_rom_gpio_pad_set_drv(d_gpio_num, drv); + esp_rom_gpio_pad_set_drv(cs0_gpio_num, drv); + if (hd_gpio_num <= MAX_PAD_GPIO_NUM) { + esp_rom_gpio_pad_set_drv(hd_gpio_num, drv); + } + if (wp_gpio_num <= MAX_PAD_GPIO_NUM) { + esp_rom_gpio_pad_set_drv(wp_gpio_num, drv); + } +} + +static void bootloader_reset_mmu(void) +{ + Cache_Suspend_ICache(); + Cache_Invalidate_ICache_All(); + Cache_MMU_Init(); + + REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_IBUS); + REG_CLR_BIT(EXTMEM_ICACHE_CTRL1_REG, EXTMEM_ICACHE_SHUT_DBUS); +} + +static void update_flash_config(const esp_image_header_t *bootloader_hdr) +{ + uint32_t size; + switch (bootloader_hdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + size = 1; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + size = 2; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + size = 4; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + size = 8; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + size = 16; + break; + default: + size = 2; + } + uint32_t autoload = Cache_Suspend_ICache(); + // Set flash chip size + esp_rom_spiflash_config_param(rom_spiflash_legacy_data->chip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); // TODO: set mode + Cache_Resume_ICache(autoload); +} + +static void print_flash_info(const esp_image_header_t *bootloader_hdr) +{ + ESP_LOGD(TAG, "magic %02x", bootloader_hdr->magic); + ESP_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count); + ESP_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode); + ESP_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed); + ESP_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size); + + const char *str; + switch (bootloader_hdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_40M: + str = "40MHz"; + break; + case ESP_IMAGE_SPI_SPEED_26M: + str = "26.7MHz"; + break; + case ESP_IMAGE_SPI_SPEED_20M: + str = "20MHz"; + break; + case ESP_IMAGE_SPI_SPEED_80M: + str = "80MHz"; + break; + default: + str = "20MHz"; + break; + } + ESP_LOGI(TAG, "SPI Speed : %s", str); + + /* SPI mode could have been set to QIO during boot already, + so test the SPI registers not the flash header */ + uint32_t spi_ctrl = REG_READ(SPI_MEM_CTRL_REG(0)); + if (spi_ctrl & SPI_MEM_FREAD_QIO) { + str = "QIO"; + } else if (spi_ctrl & SPI_MEM_FREAD_QUAD) { + str = "QOUT"; + } else if (spi_ctrl & SPI_MEM_FREAD_DIO) { + str = "DIO"; + } else if (spi_ctrl & SPI_MEM_FREAD_DUAL) { + str = "DOUT"; + } else if (spi_ctrl & SPI_MEM_FASTRD_MODE) { + str = "FAST READ"; + } else { + str = "SLOW READ"; + } + ESP_LOGI(TAG, "SPI Mode : %s", str); + + switch (bootloader_hdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + str = "1MB"; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + str = "2MB"; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + str = "4MB"; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + str = "8MB"; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + str = "16MB"; + break; + default: + str = "2MB"; + break; + } + ESP_LOGI(TAG, "SPI Flash Size : %s", str); +} + +static void IRAM_ATTR bootloader_init_flash_configure(void) +{ + bootloader_flash_dummy_config(&bootloader_image_hdr); + bootloader_flash_cs_timing_config(); +} + +static esp_err_t bootloader_init_spi_flash(void) +{ + bootloader_init_flash_configure(); +#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH + const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info(); + if (spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_SPI && spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI) { + ESP_LOGE(TAG, "SPI flash pins are overridden. Enable CONFIG_SPI_FLASH_ROM_DRIVER_PATCH in menuconfig"); + return ESP_FAIL; + } +#endif + + esp_rom_spiflash_unlock(); + +#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT + bootloader_enable_qio_mode(); +#endif + + print_flash_info(&bootloader_image_hdr); + update_flash_config(&bootloader_image_hdr); + //ensure the flash is write-protected + bootloader_enable_wp(); + return ESP_OK; +} + +static void wdt_reset_cpu0_info_enable(void) +{ + REG_SET_BIT(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); + REG_CLR_BIT(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); + REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); +} + +static void wdt_reset_info_dump(int cpu) +{ + // TODO ESP32-C3 IDF-2118 + ESP_LOGE(TAG, "WDT reset info dump is not supported yet", cpu_name); +} + +static void bootloader_check_wdt_reset(void) +{ + int wdt_rst = 0; + RESET_REASON rst_reas[2]; + + rst_reas[0] = rtc_get_reset_reason(0); + if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET || + rst_reas[0] == TG0WDT_CPU_RESET || rst_reas[0] == TG1WDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) { + ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); + wdt_rst = 1; + } + if (wdt_rst) { + // if reset by WDT dump info from trace port + wdt_reset_info_dump(0); + } + wdt_reset_cpu0_info_enable(); +} + +static void bootloader_super_wdt_auto_feed(void) +{ + REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, RTC_CNTL_SWD_WKEY_VALUE); + REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN); + REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, 0); +} + +static inline void bootloader_hardware_init(void) +{ + // TODO ESP32-C3 IDF-2452 + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1); + REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12); +} + +static inline void bootloader_glitch_reset_disable(void) +{ + // TODO ESP32-C3 IDF-2453 + REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, 0); +} + +esp_err_t bootloader_init(void) +{ + esp_err_t ret = ESP_OK; + bootloader_hardware_init(); + bootloader_glitch_reset_disable(); + bootloader_super_wdt_auto_feed(); + // protect memory region + bootloader_init_mem(); + /* check that static RAM is after the stack */ + assert(&_bss_start <= &_bss_end); + assert(&_data_start <= &_data_end); + // clear bss section + bootloader_clear_bss_section(); + // reset MMU + bootloader_reset_mmu(); + // config clock + bootloader_clock_configure(); + // initialize console, from now on, we can use esp_log + bootloader_console_init(); + /* print 2nd bootloader banner */ + bootloader_print_banner(); + // update flash ID + bootloader_flash_update_id(); + // read bootloader header + if ((ret = bootloader_read_bootloader_header()) != ESP_OK) { + goto err; + } + // read chip revision and check if it's compatible to bootloader + if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) { + goto err; + } + // initialize spi flash + if ((ret = bootloader_init_spi_flash()) != ESP_OK) { + goto err; + } + // check whether a WDT reset happend + bootloader_check_wdt_reset(); + // config WDT + bootloader_config_wdt(); + // enable RNG early entropy source + bootloader_enable_random(); +err: + return ret; +} diff --git a/components/bootloader_support/src/esp32c3/bootloader_sha.c b/components/bootloader_support/src/esp32c3/bootloader_sha.c new file mode 100644 index 0000000000..9388626e89 --- /dev/null +++ b/components/bootloader_support/src/esp32c3/bootloader_sha.c @@ -0,0 +1,48 @@ +// 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 "bootloader_sha.h" +#include +#include +#include +#include + +#include "esp32c3/rom/sha.h" + +static SHA_CTX ctx; + +bootloader_sha256_handle_t bootloader_sha256_start() +{ + // Enable SHA hardware + ets_sha_enable(); + ets_sha_init(&ctx, SHA2_256); + return &ctx; // Meaningless non-NULL value +} + +void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len) +{ + assert(handle != NULL); + assert(data_len % 4 == 0); + ets_sha_update(&ctx, data, data_len, false); +} + +void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest) +{ + assert(handle != NULL); + + if (digest == NULL) { + bzero(&ctx, sizeof(ctx)); + return; + } + ets_sha_finish(&ctx, digest); +} diff --git a/components/bootloader_support/src/esp32c3/flash_encrypt.c b/components/bootloader_support/src/esp32c3/flash_encrypt.c new file mode 100644 index 0000000000..cc45a5fbf3 --- /dev/null +++ b/components/bootloader_support/src/esp32c3/flash_encrypt.c @@ -0,0 +1,296 @@ +// 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 "bootloader_flash_priv.h" +#include "bootloader_random.h" +#include "bootloader_utility.h" +#include "esp_image_format.h" +#include "esp_flash_encrypt.h" +#include "esp_flash_partitions.h" +#include "esp_secure_boot.h" +#include "esp_log.h" +#include "esp32c3/rom/secure_boot.h" +#include "esp32c3/rom/cache.h" +#include "esp32c3/rom/efuse.h" + +static const char *TAG = "flash_encrypt"; + +/* Static functions for stages of flash encryption */ +static esp_err_t initialise_flash_encryption(void); +static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis); +static esp_err_t encrypt_bootloader(void); +static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions); +static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition); + +esp_err_t esp_flash_encrypt_check_and_update(void) +{ + // TODO ESP32-C3 IDF-2116 + uint32_t cnt = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_SPI_BOOT_CRYPT_CNT); + ESP_LOGV(TAG, "SPI_BOOT_CRYPT_CNT 0x%x", cnt); + + bool flash_crypt_wr_dis = false; // TODO: check if CRYPT_CNT is write disabled + + _Static_assert(EFUSE_SPI_BOOT_CRYPT_CNT == 0x7, "assuming CRYPT_CNT is only 3 bits wide"); + + if (cnt == 1 || cnt == 3 || cnt == 7) { + /* Flash is already encrypted */ + int left; + if (cnt == 7 /* || disabled */) { + left = 0; + } else if (cnt == 3) { + left = 1; + } else { + left = 2; + } + ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left); + return ESP_OK; + } else { + /* Flash is not encrypted, so encrypt it! */ + return encrypt_flash_contents(cnt, flash_crypt_wr_dis); + } +} + +static esp_err_t initialise_flash_encryption(void) +{ + /* Before first flash encryption pass, need to initialise key & crypto config */ + + /* Find out if a key is already set */ + bool has_aes128 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL); + bool has_aes256_1 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1, NULL); + bool has_aes256_2 = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2, NULL); + + bool has_key = has_aes128 || (has_aes256_1 && has_aes256_2); + + if (!has_key && (has_aes256_1 || has_aes256_2)) { + ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set."); + return ESP_ERR_INVALID_STATE; + } + + if (has_key) { + ESP_LOGI(TAG, "Using pre-existing key in efuse"); + + ESP_LOGE(TAG, "TODO: Check key is read & write protected"); // TODO + } else { + ESP_LOGI(TAG, "Generating new flash encryption key..."); +#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256 + const unsigned BLOCKS_NEEDED = 2; + const ets_efuse_purpose_t PURPOSE_START = ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1; + const ets_efuse_purpose_t PURPOSE_END = ETS_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2; +#else + const unsigned BLOCKS_NEEDED = 1; + const ets_efuse_purpose_t PURPOSE_START = ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY; + const ets_efuse_purpose_t PURPOSE_END = ETS_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY; +#endif + + if (ets_efuse_count_unused_key_blocks() < BLOCKS_NEEDED) { + ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED); + return ESP_ERR_INVALID_STATE; + } + + for (ets_efuse_purpose_t purpose = PURPOSE_START; purpose <= PURPOSE_END; purpose++) { + uint32_t buf[8] = {0}; + bootloader_fill_random(buf, sizeof(buf)); + ets_efuse_block_t block = ets_efuse_find_unused_key_block(); + ESP_LOGD(TAG, "Writing ETS_EFUSE_BLOCK_KEY%d with purpose %d", + block - ETS_EFUSE_BLOCK_KEY0, purpose); + bootloader_debug_buffer(buf, sizeof(buf), "Key content"); + int r = ets_efuse_write_key(block, purpose, buf, sizeof(buf)); + bzero(buf, sizeof(buf)); + if (r != 0) { + ESP_LOGE(TAG, "Failed to write efuse block %d with purpose %d. Can't continue."); + return ESP_FAIL; + } + } + ESP_LOGD(TAG, "Key generation complete"); + } + + ESP_LOGE(TAG, "TODO: burn remaining security protection bits"); + + return ESP_OK; +} + +/* Encrypt all flash data that should be encrypted */ +static esp_err_t encrypt_flash_contents(uint32_t spi_boot_crypt_cnt, bool flash_crypt_wr_dis) +{ + esp_err_t err; + esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES]; + int num_partitions; + + /* If the last spi_boot_crypt_cnt bit is burned or write-disabled, the + device can't re-encrypt itself. */ + if (flash_crypt_wr_dis || spi_boot_crypt_cnt == EFUSE_SPI_BOOT_CRYPT_CNT) { + ESP_LOGE(TAG, "Cannot re-encrypt data (SPI_BOOT_CRYPT_CNT 0x%02x write disabled %d", spi_boot_crypt_cnt, flash_crypt_wr_dis); + return ESP_FAIL; + } + + if (spi_boot_crypt_cnt == 0) { + /* Very first flash of encrypted data: generate keys, etc. */ + err = initialise_flash_encryption(); + if (err != ESP_OK) { + return err; + } + } + + err = encrypt_bootloader(); + if (err != ESP_OK) { + return err; + } + + err = encrypt_and_load_partition_table(partition_table, &num_partitions); + if (err != ESP_OK) { + return err; + } + + /* Now iterate the just-loaded partition table, looking for entries to encrypt + */ + + /* Go through each partition and encrypt if necessary */ + for (int i = 0; i < num_partitions; i++) { + err = encrypt_partition(i, &partition_table[i]); + if (err != ESP_OK) { + return err; + } + } + + ESP_LOGD(TAG, "All flash regions checked for encryption pass"); + + /* Set least significant 0-bit in spi_boot_crypt_cnt */ + int ffs_inv = __builtin_ffs((~spi_boot_crypt_cnt) & 0x7); + /* ffs_inv shouldn't be zero, as zero implies spi_boot_crypt_cnt == 0xFF */ + uint32_t new_spi_boot_crypt_cnt = spi_boot_crypt_cnt + (1 << (ffs_inv - 1)); + ESP_LOGD(TAG, "SPI_BOOT_CRYPT_CNT 0x%x -> 0x%x", spi_boot_crypt_cnt, new_spi_boot_crypt_cnt); + + ets_efuse_clear_program_registers(); + REG_SET_FIELD(EFUSE_PGM_DATA2_REG, EFUSE_SPI_BOOT_CRYPT_CNT, new_spi_boot_crypt_cnt); + ets_efuse_program(ETS_EFUSE_BLOCK0); + + ESP_LOGI(TAG, "Flash encryption completed"); + + return ESP_OK; +} + +static esp_err_t encrypt_bootloader(void) +{ + esp_err_t err; + uint32_t image_length; + /* Check for plaintext bootloader (verification will fail if it's already encrypted) */ + if (esp_image_verify_bootloader(&image_length) == ESP_OK) { + ESP_LOGD(TAG, "bootloader is plaintext. Encrypting..."); + err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err); + return err; + } + + if (esp_secure_boot_enabled()) { + // TODO: anything different for secure boot? + } + } else { + ESP_LOGW(TAG, "no valid bootloader was found"); + } + + return ESP_OK; +} + +static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions) +{ + esp_err_t err; + /* Check for plaintext partition table */ + err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to read partition table data"); + return err; + } + if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) { + ESP_LOGD(TAG, "partition table is plaintext. Encrypting..."); + esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET, + FLASH_SECTOR_SIZE); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err); + return err; + } + } else { + ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?"); + return ESP_ERR_INVALID_STATE; + } + + /* Valid partition table loaded */ + return ESP_OK; +} + +static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition) +{ + esp_err_t err; + bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED); + + if (partition->type == PART_TYPE_APP) { + /* check if the partition holds a valid unencrypted app */ + esp_image_metadata_t data_ignored; + err = esp_image_verify(ESP_IMAGE_VERIFY, + &partition->pos, + &data_ignored); + should_encrypt = (err == ESP_OK); + } else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) { + /* check if we have ota data partition and the partition should be encrypted unconditionally */ + should_encrypt = true; + } + + if (!should_encrypt) { + return ESP_OK; + } else { + /* should_encrypt */ + ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x (length 0x%x)...", index, partition->pos.offset, partition->pos.size); + + err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size); + ESP_LOGI(TAG, "Done encrypting"); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to encrypt partition %d", index); + } + return err; + } +} + +esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length) +{ + esp_err_t err; + uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)]; + + if (src_addr % FLASH_SECTOR_SIZE != 0) { + ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x", src_addr); + return ESP_FAIL; + } + + for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) { + uint32_t sec_start = i + src_addr; + err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false); + if (err != ESP_OK) { + goto flash_failed; + } + err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE); + if (err != ESP_OK) { + goto flash_failed; + } + err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true); + if (err != ESP_OK) { + goto flash_failed; + } + } + return ESP_OK; + +flash_failed: + ESP_LOGE(TAG, "flash operation failed: 0x%x", err); + return err; +} diff --git a/components/bootloader_support/src/esp32c3/secure_boot.c b/components/bootloader_support/src/esp32c3/secure_boot.c new file mode 100644 index 0000000000..ae3e2bdc1f --- /dev/null +++ b/components/bootloader_support/src/esp32c3/secure_boot.c @@ -0,0 +1,45 @@ +// 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 "esp_secure_boot.h" +#include "esp_log.h" +#include "esp32c3/rom/secure_boot.h" +#include "esp_rom_efuse.h" + +static const char *TAG = "secure_boot"; + +esp_err_t esp_secure_boot_permanently_enable(void) +{ + uint8_t hash[32]; + + if (esp_rom_efuse_is_secure_boot_enabled()) { + ESP_LOGI(TAG, "secure boot is already enabled, continuing.."); + return ESP_OK; + } + + ESP_LOGI(TAG, "Verifying bootloader signature...\n"); + int r = ets_secure_boot_verify_bootloader(hash, false); + if (r != ESP_OK) { + ESP_LOGE(TAG, "Failed to verify bootloader signature"); + return r; + } + + ets_efuse_clear_program_registers(); + REG_SET_BIT(EFUSE_PGM_DATA3_REG, EFUSE_SECURE_BOOT_EN); + ets_efuse_program(ETS_EFUSE_BLOCK0); + + assert(esp_rom_efuse_is_secure_boot_enabled()); + ESP_LOGI(TAG, "Secure boot permanently enabled"); + + return ESP_OK; +} diff --git a/components/bootloader_support/src/esp32c3/secure_boot_signatures.c b/components/bootloader_support/src/esp32c3/secure_boot_signatures.c new file mode 100644 index 0000000000..458ced12ae --- /dev/null +++ b/components/bootloader_support/src/esp32c3/secure_boot_signatures.c @@ -0,0 +1,93 @@ +// 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 "sdkconfig.h" + +#include "bootloader_flash.h" +#include "bootloader_sha.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "esp32c3/rom/secure_boot.h" + +static const char *TAG = "secure_boot"; + +#define DIGEST_LEN 32 + +esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) +{ + ets_secure_boot_key_digests_t trusted_keys = { 0 }; + uint8_t digest[DIGEST_LEN]; + const uint8_t *data; + + ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length); + + if ((src_addr + length) % 4096 != 0) { + ESP_LOGE(TAG, "addr 0x%x length 0x%x doesn't end on a sector boundary", src_addr, length); + return ESP_ERR_INVALID_ARG; + } + + data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block)); + if (data == NULL) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length + sizeof(ets_secure_boot_signature_t)); + return ESP_FAIL; + } + + // Calculate digest of main image +#ifdef BOOTLOADER_BUILD + bootloader_sha256_handle_t handle = bootloader_sha256_start(); + bootloader_sha256_data(handle, data, length); + bootloader_sha256_finish(handle, digest); +#else + /* Use thread-safe esp-idf SHA function */ + esp_sha(SHA2_256, data, length, digest); +#endif + + int r = ets_secure_boot_read_key_digests(&trusted_keys); + + if (r == ETS_OK) { + const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length); + // TODO: calling this function in IDF app context is unsafe + r = ets_secure_boot_verify_signature(sig, digest, &trusted_keys); + } + bootloader_munmap(data); + + return (r == ETS_OK) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_secure_boot_verify_signature_block(uint32_t sig_block_flash_offs, const uint8_t *image_digest) +{ + ets_secure_boot_key_digests_t trusted_keys; + + assert(sig_block_flash_offs % 4096 == 0); // TODO: enforce this in a better way + + const ets_secure_boot_signature_t *sig = bootloader_mmap(sig_block_flash_offs, sizeof(ets_secure_boot_signature_t)); + + if (sig == NULL) { + ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", sig_block_flash_offs); + return ESP_FAIL; + } + + int r = ets_secure_boot_read_key_digests(&trusted_keys); + if (r != 0) { + ESP_LOGE(TAG, "No trusted key digests were found in efuse!"); + } else { + ESP_LOGD(TAG, "Verifying with RSA-PSS..."); + // TODO: calling this function in IDF app context is unsafe + r = ets_secure_boot_verify_signature(sig, image_digest, &trusted_keys); + } + + bootloader_munmap(sig); + + return (r == 0) ? ESP_OK : ESP_ERR_IMAGE_INVALID; +} diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index e61972f573..9ed8b140c1 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -607,6 +607,11 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui // Set up the obfuscation value to use for loading while (ram_obfs_value[0] == 0 || ram_obfs_value[1] == 0) { bootloader_fill_random(ram_obfs_value, sizeof(ram_obfs_value)); +#if CONFIG_IDF_ENV_FPGA + /* FPGA doesn't always emulate the RNG */ + ram_obfs_value[0] ^= 0x33; + ram_obfs_value[1] ^= 0x66; +#endif } uint32_t *dest = (uint32_t *)load_addr; #endif diff --git a/components/bootloader_support/test/test_verify_image.c b/components/bootloader_support/test/test_verify_image.c index fd6cef02ff..cd87c719ab 100644 --- a/components/bootloader_support/test/test_verify_image.c +++ b/components/bootloader_support/test/test_verify_image.c @@ -10,7 +10,6 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/queue.h" -#include "freertos/xtensa_api.h" #include "unity.h" #include "bootloader_common.h" #include "bootloader_util.h" From c39476d6993cb26fb7e5609282837221f977abc4 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 2 Dec 2020 11:43:13 +0800 Subject: [PATCH 4/4] esp_rom: added esp_rom_install_uart_printf --- components/esp_rom/esp32/esp_rom_caps.h | 7 ++++--- components/esp_rom/esp32/ld/esp32.rom.api.ld | 1 + components/esp_rom/esp32c3/esp_rom_caps.h | 7 ++++--- components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld | 3 +-- components/esp_rom/esp32s2/esp_rom_caps.h | 3 ++- components/esp_rom/esp32s2/ld/esp32s2.rom.api.ld | 1 + components/esp_rom/esp32s3/esp_rom_caps.h | 8 +++++--- components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld | 1 + components/esp_rom/include/esp_rom_sys.h | 5 +++++ components/esp_system/port/cpu_start.c | 2 +- 10 files changed, 25 insertions(+), 13 deletions(-) diff --git a/components/esp_rom/esp32/esp_rom_caps.h b/components/esp_rom/esp32/esp_rom_caps.h index f6fd1edd09..6188ef52a7 100644 --- a/components/esp_rom/esp32/esp_rom_caps.h +++ b/components/esp_rom/esp32/esp_rom_caps.h @@ -14,6 +14,7 @@ #pragma once -#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian -#define ESP_ROM_HAS_CRC_BE (1) // ROM CRC library supports Big Endian -#define ESP_ROM_HAS_JPEG_DECODE (1) // ROM has JPEG decode library +#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian +#define ESP_ROM_HAS_CRC_BE (1) // ROM CRC library supports Big Endian +#define ESP_ROM_HAS_JPEG_DECODE (1) // ROM has JPEG decode library +#define ESP_ROM_SUPPORT_MULTIPLE_UART (1) // ROM has multiple UARTs available for logging diff --git a/components/esp_rom/esp32/ld/esp32.rom.api.ld b/components/esp_rom/esp32/ld/esp32.rom.api.ld index f3904f81d7..cf0b143fa2 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.api.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.api.ld @@ -36,3 +36,4 @@ PROVIDE ( esp_rom_md5_final = 0x4005db1c ); PROVIDE ( esp_rom_printf = ets_printf ); PROVIDE ( esp_rom_delay_us = ets_delay_us ); +PROVIDE ( esp_rom_install_uart_printf = ets_install_uart_printf ); diff --git a/components/esp_rom/esp32c3/esp_rom_caps.h b/components/esp_rom/esp32c3/esp_rom_caps.h index f6fd1edd09..bae770da81 100644 --- a/components/esp_rom/esp32c3/esp_rom_caps.h +++ b/components/esp_rom/esp32c3/esp_rom_caps.h @@ -14,6 +14,7 @@ #pragma once -#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian -#define ESP_ROM_HAS_CRC_BE (1) // ROM CRC library supports Big Endian -#define ESP_ROM_HAS_JPEG_DECODE (1) // ROM has JPEG decode library +#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian +#define ESP_ROM_HAS_CRC_BE (1) // ROM CRC library supports Big Endian +#define ESP_ROM_HAS_JPEG_DECODE (1) // ROM has JPEG decode library +#define ESP_ROM_UART_CLK_IS_XTAL (1) // UART clock source is selected to XTAL in ROM diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld index 3ebd5380b2..263da9b726 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld @@ -24,8 +24,6 @@ PROVIDE ( esp_rom_uart_tx_one_char = uart_tx_one_char ); PROVIDE ( esp_rom_uart_tx_wait_idle = uart_tx_wait_idle ); PROVIDE ( esp_rom_uart_rx_one_char = uart_rx_one_char ); PROVIDE ( esp_rom_uart_rx_string = UartRxString ); -PROVIDE ( esp_rom_uart_set_as_console = uart_tx_switch ); -PROVIDE ( esp_rom_uart_putc = ets_write_char_uart ); PROVIDE ( esp_rom_md5_init = MD5Init ); PROVIDE ( esp_rom_md5_update = MD5Update ); @@ -33,3 +31,4 @@ PROVIDE ( esp_rom_md5_final = MD5Final ); PROVIDE ( esp_rom_printf = ets_printf ); PROVIDE ( esp_rom_delay_us = ets_delay_us ); +PROVIDE ( esp_rom_install_uart_printf = ets_install_uart_printf ); diff --git a/components/esp_rom/esp32s2/esp_rom_caps.h b/components/esp_rom/esp32s2/esp_rom_caps.h index e699f431d1..0f63dfb542 100644 --- a/components/esp_rom/esp32s2/esp_rom_caps.h +++ b/components/esp_rom/esp32s2/esp_rom_caps.h @@ -14,4 +14,5 @@ #pragma once -#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian +#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian +#define ESP_ROM_SUPPORT_MULTIPLE_UART (1) // ROM has multiple UARTs available for logging diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.api.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.api.ld index c96a54feff..63ad6e6d6f 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.api.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.api.ld @@ -35,3 +35,4 @@ PROVIDE ( esp_rom_md5_final = 0x4000530c ); PROVIDE ( esp_rom_printf = ets_printf ); PROVIDE ( esp_rom_delay_us = ets_delay_us ); +PROVIDE ( esp_rom_install_uart_printf = ets_install_uart_printf ); diff --git a/components/esp_rom/esp32s3/esp_rom_caps.h b/components/esp_rom/esp32s3/esp_rom_caps.h index f6fd1edd09..aee488a025 100644 --- a/components/esp_rom/esp32s3/esp_rom_caps.h +++ b/components/esp_rom/esp32s3/esp_rom_caps.h @@ -14,6 +14,8 @@ #pragma once -#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian -#define ESP_ROM_HAS_CRC_BE (1) // ROM CRC library supports Big Endian -#define ESP_ROM_HAS_JPEG_DECODE (1) // ROM has JPEG decode library +#define ESP_ROM_HAS_CRC_LE (1) // ROM CRC library supports Little Endian +#define ESP_ROM_HAS_CRC_BE (1) // ROM CRC library supports Big Endian +#define ESP_ROM_HAS_JPEG_DECODE (1) // ROM has JPEG decode library +#define ESP_ROM_SUPPORT_MULTIPLE_UART (1) // ROM has multiple UARTs available for logging +#define ESP_ROM_UART_CLK_IS_XTAL (1) // UART clock source is selected to XTAL in ROM diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld index 592faa8fe9..91dfe43914 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld @@ -38,3 +38,4 @@ PROVIDE ( esp_rom_md5_final = 0x40037740 ); PROVIDE ( esp_rom_printf = ets_printf ); PROVIDE ( esp_rom_delay_us = ets_delay_us ); +PROVIDE ( esp_rom_install_uart_printf = ets_install_uart_printf ); diff --git a/components/esp_rom/include/esp_rom_sys.h b/components/esp_rom/include/esp_rom_sys.h index ef85d35abf..130c307014 100644 --- a/components/esp_rom/include/esp_rom_sys.h +++ b/components/esp_rom/include/esp_rom_sys.h @@ -51,6 +51,11 @@ void esp_rom_install_channel_putc(int channel, void (*putc)(char c)); */ void esp_rom_disable_logging(void); +/** + * @brief Install UART1 as the default console channel, equivalent to `esp_rom_install_channel_putc(1, esp_rom_uart_putc)` + */ +void esp_rom_install_uart_printf(void); + #ifdef __cplusplus } #endif diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index bbdc7e0f0c..99a43309b1 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -141,7 +141,7 @@ void IRAM_ATTR call_start_cpu1(void) esp_rom_install_channel_putc(1, NULL); esp_rom_install_channel_putc(2, NULL); #else // CONFIG_ESP_CONSOLE_UART_NONE - ets_install_uart_printf(); + esp_rom_install_uart_printf(); esp_rom_uart_set_as_console(CONFIG_ESP_CONSOLE_UART_NUM); #endif