Merge branch 'master' into feature/openssl

This commit is contained in:
Dong Heng 2016-11-15 15:20:48 +08:00
commit 4d25986aaa
101 changed files with 3304 additions and 1236 deletions

3
.gitmodules vendored
View file

@ -7,3 +7,6 @@
[submodule "components/bt/lib"] [submodule "components/bt/lib"]
path = components/bt/lib path = components/bt/lib
url = https://github.com/espressif/esp32-bt-lib.git url = https://github.com/espressif/esp32-bt-lib.git
[submodule "components/micro-ecc/micro-ecc"]
path = components/micro-ecc/micro-ecc
url = https://github.com/kmackay/micro-ecc.git

View file

@ -29,3 +29,90 @@ config LOG_BOOTLOADER_LEVEL
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
endmenu endmenu
menu "Secure boot configuration"
choice SECURE_BOOTLOADER
bool "Secure bootloader"
default SECURE_BOOTLOADER_DISABLED
help
Build a bootloader with the secure boot flag enabled.
Secure bootloader can be one-time-flash (chip will only ever
boot that particular bootloader), or a digest key can be used
to allow the secure bootloader to be re-flashed with
modifications. Secure boot also permanently disables JTAG.
See docs/security/secure-boot.rst for details.
config SECURE_BOOTLOADER_DISABLED
bool "Disabled"
config SECURE_BOOTLOADER_ONE_TIME_FLASH
bool "One-time flash"
help
On first boot, the bootloader will generate a key which is not readable externally or by software. A digest is generated from the bootloader image itself. This digest will be verified on each subsequent boot.
Enabling this option means that the bootloader cannot be changed after the first time it is booted.
config SECURE_BOOTLOADER_REFLASHABLE
bool "Reflashable"
help
Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key.
This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing key.
This option is less secure than one-time flash, because a leak of the digest key from one device allows reflashing of any device that uses it.
endchoice
config SECURE_BOOT_SIGNING_KEY
string "Secure boot signing key"
depends on SECURE_BOOTLOADER_ENABLED
default secure_boot_signing_key.pem
help
Path to the key file used to sign partition tables and app images for secure boot.
Key file is an ECDSA private key (NIST256p curve) in PEM format.
Path is evaluated relative to the project directory.
You can generate a new signing key by running the following command:
espsecure.py generate_signing_key secure_boot_signing_key.pem
See docs/security/secure-boot.rst for details.
config SECURE_BOOT_DISABLE_JTAG
bool "First boot: Permanently disable JTAG"
depends on SECURE_BOOTLOADER_ENABLED
default Y
help
Bootloader permanently disable JTAG (across entire chip) when enabling secure boot. This happens on first boot of the bootloader.
It is recommended this option remains set for production environments.
config SECURE_BOOT_DISABLE_ROM_BASIC
bool "First boot: Permanently disable ROM BASIC fallback"
depends on SECURE_BOOTLOADER_ENABLED
default Y
help
Bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot.
It is recommended this option remains set in production environments.
config SECURE_BOOT_TEST_MODE
bool "Test mode: don't actually enable secure boot"
depends on SECURE_BOOTLOADER_ENABLED
default N
help
If this option is set, all permanent secure boot changes (via Efuse) are disabled.
This option is for testing purposes only - it effectively completely disables secure boot protection.
config SECURE_BOOTLOADER_ENABLED
bool
default SECURE_BOOTLOADER_ONE_TIME_FLASH || SECURE_BOOTLOADER_REFLASHABLE
endmenu

View file

@ -13,43 +13,108 @@ ifndef IS_BOOTLOADER_BUILD
BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH) BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader) BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
BOOTLOADER_SDKCONFIG=$(BOOTLOADER_BUILD_DIR)/sdkconfig
# signing key path is resolved relative to the project directory
SECURE_BOOT_SIGNING_KEY=$(abspath $(call dequote,$(CONFIG_SECURE_BOOT_SIGNING_KEY)))
export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component
# Custom recursive make for bootloader sub-project # Custom recursive make for bootloader sub-project
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \ BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
V=$(V) SDKCONFIG=$(BOOTLOADER_SDKCONFIG) \ V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR)
BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN) .PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
$(BOOTLOADER_BIN): | $(BOOTLOADER_BUILD_DIR)/sdkconfig $(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE)
$(Q) $(BOOTLOADER_MAKE) $@ $(BOOTLOADER_MAKE) $@
bootloader-clean:
$(Q) $(BOOTLOADER_MAKE) app-clean config-clean
$(Q) rm -f $(BOOTLOADER_SDKCONFIG) $(BOOTLOADER_SDKCONFIG).old
clean: bootloader-clean clean: bootloader-clean
ifdef CONFIG_SECURE_BOOTLOADER_DISABLED
# If secure boot disabled, bootloader flashing is integrated
# with 'make flash' and no warnings are printed.
bootloader: $(BOOTLOADER_BIN) bootloader: $(BOOTLOADER_BIN)
@echo $(SEPARATOR)
@echo "Bootloader built. Default flash command is:" @echo "Bootloader built. Default flash command is:"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^" @echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^"
all_binaries: $(BOOTLOADER_BIN)
ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN) ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN)
# bootloader-flash calls flash in the bootloader dummy project
bootloader-flash: $(BOOTLOADER_BIN) bootloader-flash: $(BOOTLOADER_BIN)
$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^ $(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
# synchronise the project level config to the bootloader's else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
# config
$(BOOTLOADER_SDKCONFIG): $(PROJECT_PATH)/sdkconfig | $(BOOTLOADER_BUILD_DIR) #### TEMPORARILY DISABLE THIS OPTION
$(Q) cp $< $@ ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1")
bootloader:
@echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device"
@echo "If you flash this bootloader, you will be left with an non-updateable bootloader that is missing features."
@echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make."
exit 1
else
# One time flashing requires user to run esptool.py command themselves,
# and warning is printed about inability to reflash.
bootloader: $(BOOTLOADER_BIN)
@echo $(SEPARATOR)
@echo "Bootloader built. One-time flash command is:"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
@echo $(SEPARATOR)
@echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
endif # IDF_INSECURE_SECURE_BOOT
else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
# Reflashable secure bootloader
# generates a digest binary (bootloader + digest)
#### TEMPORARILY DISABLE THIS OPTION
ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1")
bootloader:
@echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device."
@echo "If using this feature, expect to reflash the bootloader at least one more time."
@echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make."
exit 1
else
BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY)
$(Q) $(ESPSECUREPY) digest_private_key -k $< $@
bootloader: $(BOOTLOADER_DIGEST_BIN)
@echo $(SEPARATOR)
@echo "Bootloader built and secure digest generated. First time flash command is:"
@echo "$(ESPEFUSEPY) burn_key secure_boot $(SECURE_BOOTLOADER_KEY)"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
@echo $(SEPARATOR)
@echo "To reflash the bootloader after initial flash:"
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x0 $(BOOTLOADER_DIGEST_BIN)"
@echo $(SEPARATOR)
@echo "* After first boot, only re-flashes of this kind (with same key) will be accepted."
@echo "* Not recommended to re-use the same secure boot keyfile on multiple production devices."
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY)
@echo "DIGEST $(notdir $@)"
$(Q) $(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<
endif # IDF_INSECURE_SECURE_BOOT
else
bootloader:
@echo "Invalid bootloader target: bad sdkconfig?"
@exit 1
endif
all_binaries: $(BOOTLOADER_BIN)
bootloader-clean:
$(BOOTLOADER_MAKE) app-clean
rm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN)
$(BOOTLOADER_BUILD_DIR): $(BOOTLOADER_BUILD_DIR):
$(Q) mkdir -p $@ mkdir -p $@
else else
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include

View file

@ -4,7 +4,10 @@
# #
PROJECT_NAME := bootloader PROJECT_NAME := bootloader
COMPONENTS := esptool_py bootloader log spi_flash
#We cannot include the esp32 component directly but we need its includes.
#This is fixed by adding CFLAGS from Makefile.projbuild
COMPONENTS := esptool_py bootloader bootloader_support log spi_flash micro-ecc
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included. # The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
# #
@ -12,7 +15,7 @@ COMPONENTS := esptool_py bootloader log spi_flash
IS_BOOTLOADER_BUILD := 1 IS_BOOTLOADER_BUILD := 1
export IS_BOOTLOADER_BUILD export IS_BOOTLOADER_BUILD
#We cannot include the esp32 component directly but we need its includes. # include the top-level "project" include directory, for sdkconfig.h
#This is fixed by adding CFLAGS from Makefile.projbuild CFLAGS += -I$(BUILD_DIR_BASE)/../include
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk

View file

@ -25,8 +25,6 @@ extern "C"
#define BOOT_VERSION "V0.1" #define BOOT_VERSION "V0.1"
#define SPI_SEC_SIZE 0x1000 #define SPI_SEC_SIZE 0x1000
#define MEM_CACHE(offset) (uint8_t *)(0x3f400000 + (offset))
#define CACHE_READ_32(offset) ((uint32_t *)(0x3f400000 + (offset)))
#define IROM_LOW 0x400D0000 #define IROM_LOW 0x400D0000
#define IROM_HIGH 0x40400000 #define IROM_HIGH 0x40400000
#define DROM_LOW 0x3F400000 #define DROM_LOW 0x3F400000
@ -36,7 +34,6 @@ extern "C"
#define RTC_DATA_LOW 0x50000000 #define RTC_DATA_LOW 0x50000000
#define RTC_DATA_HIGH 0x50002000 #define RTC_DATA_HIGH 0x50002000
#define PART_TYPE_APP 0x00 #define PART_TYPE_APP 0x00
#define PART_SUBTYPE_FACTORY 0x00 #define PART_SUBTYPE_FACTORY 0x00
#define PART_SUBTYPE_OTA_FLAG 0x10 #define PART_SUBTYPE_OTA_FLAG 0x10
@ -62,12 +59,7 @@ typedef struct {
uint32_t selected_subtype; uint32_t selected_subtype;
} bootloader_state_t; } bootloader_state_t;
void boot_cache_redirect( uint32_t pos, size_t size );
uint32_t get_bin_len(uint32_t pos);
bool flash_encrypt(bootloader_state_t *bs); bool flash_encrypt(bootloader_state_t *bs);
bool secure_boot(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -33,6 +33,9 @@
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "bootloader_flash.h"
#include "bootloader_config.h" #include "bootloader_config.h"
@ -49,7 +52,7 @@ flash cache is down and the app CPU is in reset. We do have a stack, so we can d
extern void Cache_Flush(int); extern void Cache_Flush(int);
void bootloader_main(); void bootloader_main();
void unpack_load_app(const esp_partition_pos_t *app_node); static void unpack_load_app(const esp_partition_pos_t *app_node);
void print_flash_info(const esp_image_header_t* pfhdr); void print_flash_info(const esp_image_header_t* pfhdr);
void set_cache_and_start_app(uint32_t drom_addr, void set_cache_and_start_app(uint32_t drom_addr,
uint32_t drom_load_addr, uint32_t drom_load_addr,
@ -94,53 +97,6 @@ void IRAM_ATTR call_start_cpu0()
bootloader_main(); bootloader_main();
} }
/**
* @function : get_bin_len
* @description: get bin's length
*
* @inputs: pos bin locate address in flash
* @return: uint32 length of bin,if bin MAGIC error return 0
*/
uint32_t get_bin_len(uint32_t pos)
{
uint32_t len = 8 + 16;
uint8_t i;
ESP_LOGD(TAG, "pos %d %x",pos,*(uint8_t *)pos);
if(0xE9 != *(uint8_t *)pos) {
return 0;
}
for (i = 0; i < *(uint8_t *)(pos + 1); i++) {
len += *(uint32_t *)(pos + len + 4) + 8;
}
if (len % 16 != 0) {
len = (len / 16 + 1) * 16;
} else {
len += 16;
}
ESP_LOGD(TAG, "bin length = %d", len);
return len;
}
/**
* @function : boot_cache_redirect
* @description: Configure several pages in flash map so that `size` bytes
* starting at `pos` are mapped to 0x3f400000.
* This sets up mapping only for PRO CPU.
*
* @inputs: pos address in flash
* size size of the area to map, in bytes
*/
void boot_cache_redirect( uint32_t pos, size_t size )
{
uint32_t pos_aligned = pos & 0xffff0000;
uint32_t count = (size + 0xffff) / 0x10000;
Cache_Read_Disable( 0 );
Cache_Flush( 0 );
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", pos_aligned, count );
cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count );
Cache_Read_Enable( 0 );
}
/** /**
* @function : load_partition_table * @function : load_partition_table
@ -148,42 +104,65 @@ void boot_cache_redirect( uint32_t pos, size_t size )
* OTA info sector, factory app sector, and test app sector. * OTA info sector, factory app sector, and test app sector.
* *
* @inputs: bs bootloader state structure used to save the data * @inputs: bs bootloader state structure used to save the data
* addr address of partition table in flash
* @return: return true, if the partition table is loaded (and MD5 checksum is valid) * @return: return true, if the partition table is loaded (and MD5 checksum is valid)
* *
*/ */
bool load_partition_table(bootloader_state_t* bs, uint32_t addr) bool load_partition_table(bootloader_state_t* bs)
{ {
esp_partition_info_t partition; const esp_partition_info_t *partitions;
uint32_t end = addr + 0x1000; const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
int index = 0; const int MAX_PARTITIONS = ESP_PARTITION_TABLE_DATA_LEN / sizeof(esp_partition_info_t);
char *partition_usage; char *partition_usage;
ESP_LOGI(TAG, "Partition Table:"); ESP_LOGI(TAG, "Partition Table:");
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length"); ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
while (addr < end) { #ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
ESP_LOGD(TAG, "load partition table entry from %x(%08x)", addr, MEM_CACHE(addr)); if(esp_secure_boot_enabled()) {
memcpy(&partition, MEM_CACHE(addr), sizeof(partition)); ESP_LOGI(TAG, "Verifying partition table signature...");
ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype); esp_err_t err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to verify partition table signature.");
return false;
}
ESP_LOGD(TAG, "Partition table signature verified");
}
#endif
partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
if (!partitions) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
return false;
}
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);
for(int i = 0; i < MAX_PARTITIONS; i++) {
const esp_partition_info_t *partition = &partitions[i];
ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
partition_usage = "unknown"; partition_usage = "unknown";
if (partition.magic == ESP_PARTITION_MAGIC) { /* valid partition definition */ if (partition->magic != ESP_PARTITION_MAGIC) {
switch(partition.type) { /* invalid partition definition indicates end-of-table */
break;
}
/* valid partition table */
switch(partition->type) {
case PART_TYPE_APP: /* app partition */ case PART_TYPE_APP: /* app partition */
switch(partition.subtype) { switch(partition->subtype) {
case PART_SUBTYPE_FACTORY: /* factory binary */ case PART_SUBTYPE_FACTORY: /* factory binary */
bs->factory = partition.pos; bs->factory = partition->pos;
partition_usage = "factory app"; partition_usage = "factory app";
break; break;
case PART_SUBTYPE_TEST: /* test binary */ case PART_SUBTYPE_TEST: /* test binary */
bs->test = partition.pos; bs->test = partition->pos;
partition_usage = "test app"; partition_usage = "test app";
break; break;
default: default:
/* OTA binary */ /* OTA binary */
if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) { if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos; bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
++bs->app_count; ++bs->app_count;
partition_usage = "OTA app"; partition_usage = "OTA app";
} }
@ -194,9 +173,9 @@ bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
} }
break; /* PART_TYPE_APP */ break; /* PART_TYPE_APP */
case PART_TYPE_DATA: /* data partition */ case PART_TYPE_DATA: /* data partition */
switch(partition.subtype) { switch(partition->subtype) {
case PART_SUBTYPE_DATA_OTA: /* ota data */ case PART_SUBTYPE_DATA_OTA: /* ota data */
bs->ota_info = partition.pos; bs->ota_info = partition->pos;
partition_usage = "OTA data"; partition_usage = "OTA data";
break; break;
case PART_SUBTYPE_DATA_RF: case PART_SUBTYPE_DATA_RF:
@ -213,20 +192,15 @@ bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
default: /* other partition type */ default: /* other partition type */
break; break;
} }
}
/* invalid partition magic number */
else {
break; /* todo: validate md5 */
}
/* print partition type info */ /* print partition type info */
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage, ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage,
partition.type, partition.subtype, partition->type, partition->subtype,
partition.pos.offset, partition.pos.size); partition->pos.offset, partition->pos.size);
index++;
addr += sizeof(partition);
} }
bootloader_munmap(partitions);
ESP_LOGI(TAG,"End of partition table"); ESP_LOGI(TAG,"End of partition table");
return true; return true;
} }
@ -256,6 +230,8 @@ void bootloader_main()
bootloader_state_t bs; bootloader_state_t bs;
SpiFlashOpResult spiRet1,spiRet2; SpiFlashOpResult spiRet1,spiRet2;
esp_ota_select_entry_t sa,sb; esp_ota_select_entry_t sa,sb;
const esp_ota_select_entry_t *ota_select_map;
memset(&bs, 0, sizeof(bs)); memset(&bs, 0, sizeof(bs));
ESP_LOGI(TAG, "compile time " __TIME__ ); ESP_LOGI(TAG, "compile time " __TIME__ );
@ -263,16 +239,17 @@ void bootloader_main()
REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
SPIUnlock(); SPIUnlock();
/*register first sector in drom0 page 0 */
boot_cache_redirect( 0, 0x5000 );
memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(esp_image_header_t) ); if(esp_image_load_header(0x1000, &fhdr) != ESP_OK) {
ESP_LOGE(TAG, "failed to load bootloader header!");
return;
}
print_flash_info(&fhdr); print_flash_info(&fhdr);
update_flash_config(&fhdr); update_flash_config(&fhdr);
if (!load_partition_table(&bs, ESP_PARTITION_TABLE_ADDR)) { if (!load_partition_table(&bs)) {
ESP_LOGE(TAG, "load partition table error!"); ESP_LOGE(TAG, "load partition table error!");
return; return;
} }
@ -281,9 +258,19 @@ void bootloader_main()
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
//ESP_LOGE("OTA info sector handling is not implemented"); //ESP_LOGE("OTA info sector handling is not implemented");
boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size ); if (bs.ota_info.size < 2 * sizeof(esp_ota_select_entry_t)) {
memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa)); ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t));
memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb)); return;
}
ota_select_map = bootloader_mmap(bs.ota_info.offset, bs.ota_info.size);
if (!ota_select_map) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size);
return;
}
sa = ota_select_map[0];
sb = ota_select_map[1];
bootloader_munmap(ota_select_map);
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) { if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
// init status flash // init status flash
load_part_pos = bs.ota[0]; load_part_pos = bs.ota[0];
@ -329,13 +316,18 @@ void bootloader_main()
} }
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos); ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
if(fhdr.secure_boot_flag == 0x01) {
/* protect the 2nd_boot */ #ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
if(false == secure_boot()){ /* Generate secure digest from this bootloader to protect future
ESP_LOGE(TAG, "secure boot failed"); modifications */
return; esp_err_t err = esp_secure_boot_permanently_enable();
} if (err != ESP_OK) {
ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
/* Allow booting to continue, as the failure is probably
due to user-configured EFUSEs for testing...
*/
} }
#endif
if(fhdr.encrypt_flag == 0x01) { if(fhdr.encrypt_flag == 0x01) {
/* encrypt flash */ /* encrypt flash */
@ -345,19 +337,40 @@ void bootloader_main()
} }
} }
// copy sections to RAM, set up caches, and start application // copy loaded segments to RAM, set up caches for mapped segments, and start application
unpack_load_app(&load_part_pos); unpack_load_app(&load_part_pos);
} }
void unpack_load_app(const esp_partition_pos_t* partition) static void unpack_load_app(const esp_partition_pos_t* partition)
{ {
boot_cache_redirect(partition->offset, partition->size); esp_err_t err;
uint32_t pos = 0;
esp_image_header_t image_header; esp_image_header_t image_header;
memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header)); uint32_t image_length;
pos += sizeof(image_header);
/* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */
err = esp_image_basic_verify(partition->offset, &image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
return;
}
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, image_length);
err = esp_secure_boot_verify_signature(partition->offset, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err);
return;
}
ESP_LOGD(TAG, "App signature is valid");
}
#endif
if (esp_image_load_header(partition->offset, &image_header) != ESP_OK) {
ESP_LOGE(TAG, "Failed to load app image header @ 0x%x", partition->offset);
return;
}
uint32_t drom_addr = 0; uint32_t drom_addr = 0;
uint32_t drom_load_addr = 0; uint32_t drom_load_addr = 0;
@ -366,24 +379,27 @@ void unpack_load_app(const esp_partition_pos_t* partition)
uint32_t irom_load_addr = 0; uint32_t irom_load_addr = 0;
uint32_t irom_size = 0; uint32_t irom_size = 0;
/* Reload the RTC memory sections whenever a non-deepsleep reset /* Reload the RTC memory segments whenever a non-deepsleep reset
is occurring */ is occurring */
bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET; bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic, ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
image_header.blocks, image_header.segment_count,
image_header.spi_mode, image_header.spi_mode,
image_header.spi_size, image_header.spi_size,
(unsigned)image_header.entry_addr); (unsigned)image_header.entry_addr);
for (uint32_t section_index = 0; for (int segment = 0; segment < image_header.segment_count; segment++) {
section_index < image_header.blocks; esp_image_segment_header_t segment_header;
++section_index) { uint32_t data_offs;
esp_image_section_header_t section_header = {0}; if(esp_image_load_segment_header(segment, partition->offset,
memcpy(&section_header, MEM_CACHE(pos), sizeof(section_header)); &image_header, &segment_header,
pos += sizeof(section_header); &data_offs) != ESP_OK) {
ESP_LOGE(TAG, "failed to load segment header #%d", segment);
return;
}
const uint32_t address = section_header.load_addr; const uint32_t address = segment_header.load_addr;
bool load = true; bool load = true;
bool map = false; bool map = false;
if (address == 0x00000000) { // padding, ignore block if (address == 0x00000000) { // padding, ignore block
@ -395,45 +411,48 @@ void unpack_load_app(const esp_partition_pos_t* partition)
} }
if (address >= DROM_LOW && address < DROM_HIGH) { if (address >= DROM_LOW && address < DROM_HIGH) {
ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos, ESP_LOGD(TAG, "found drom segment, map from %08x to %08x", data_offs,
section_header.load_addr); segment_header.load_addr);
drom_addr = partition->offset + pos - sizeof(section_header); drom_addr = data_offs;
drom_load_addr = section_header.load_addr; drom_load_addr = segment_header.load_addr;
drom_size = section_header.data_len + sizeof(section_header); drom_size = segment_header.data_len + sizeof(segment_header);
load = false; load = false;
map = true; map = true;
} }
if (address >= IROM_LOW && address < IROM_HIGH) { if (address >= IROM_LOW && address < IROM_HIGH) {
ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos, ESP_LOGD(TAG, "found irom segment, map from %08x to %08x", data_offs,
section_header.load_addr); segment_header.load_addr);
irom_addr = partition->offset + pos - sizeof(section_header); irom_addr = data_offs;
irom_load_addr = section_header.load_addr; irom_load_addr = segment_header.load_addr;
irom_size = section_header.data_len + sizeof(section_header); irom_size = segment_header.data_len + sizeof(segment_header);
load = false; load = false;
map = true; map = true;
} }
if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) { if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos); ESP_LOGD(TAG, "Skipping RTC code segment at %08x\n", data_offs);
load = false; load = false;
} }
if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) { if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) {
ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos); ESP_LOGD(TAG, "Skipping RTC data segment at %08x\n", data_offs);
load = false; load = false;
} }
ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos, ESP_LOGI(TAG, "segment %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", segment, data_offs - sizeof(esp_image_segment_header_t),
section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":""); segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":"");
if (!load) { if (load) {
pos += section_header.data_len; const void *data = bootloader_mmap(data_offs, segment_header.data_len);
continue; if(!data) {
ESP_LOGE(TAG, "bootloader_mmap(0x%xc, 0x%x) failed",
data_offs, segment_header.data_len);
return;
}
memcpy((void *)segment_header.load_addr, data, segment_header.data_len);
bootloader_munmap(data);
} }
memcpy((void*) section_header.load_addr, MEM_CACHE(pos), section_header.data_len);
pos += section_header.data_len;
} }
set_cache_and_start_app(drom_addr, set_cache_and_start_app(drom_addr,
@ -520,7 +539,7 @@ void print_flash_info(const esp_image_header_t* phdr)
#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE) #if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
ESP_LOGD(TAG, "magic %02x", phdr->magic ); ESP_LOGD(TAG, "magic %02x", phdr->magic );
ESP_LOGD(TAG, "blocks %02x", phdr->blocks ); ESP_LOGD(TAG, "segments %02x", phdr->segment_count );
ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode ); ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed ); ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size ); ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );

View file

@ -1,12 +1,9 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main bootloader Makefile.
# #
# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, # This is basically the same as a component makefile, but in the case of the bootloader
# this will take the sources in the src/ directory, compile them and link them into # we pull in bootloader-specific linker arguments.
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the esp-idf build system document if you need to do this.
# #
COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld
include $(IDF_PATH)/make/component_common.mk

View file

@ -17,6 +17,7 @@
#include "esp_types.h" #include "esp_types.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_err.h"
#include "rom/cache.h" #include "rom/cache.h"
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
@ -30,6 +31,7 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "bootloader_config.h" #include "bootloader_config.h"
#include "esp_image_format.h"
static const char* TAG = "flash_encrypt"; static const char* TAG = "flash_encrypt";
@ -90,6 +92,8 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
Cache_Read_Enable(0); Cache_Read_Enable(0);
return true; return true;
} }
/** /**
* @function : flash_encrypt * @function : flash_encrypt
* @description: encrypt 2nd boot ,partition table ,factory bin <EFBFBD><EFBFBD>test bin (if use)<EFBFBD><EFBFBD>ota bin * @description: encrypt 2nd boot ,partition table ,factory bin <EFBFBD><EFBFBD>test bin (if use)<EFBFBD><EFBFBD>ota bin
@ -102,24 +106,23 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
*/ */
bool flash_encrypt(bootloader_state_t *bs) bool flash_encrypt(bootloader_state_t *bs)
{ {
uint32_t bin_len = 0; esp_err_t err;
uint32_t image_len = 0;
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT); uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
uint8_t count = bitcount(flash_crypt_cnt); uint8_t count = bitcount(flash_crypt_cnt);
int i = 0;
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count); ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
if ((count % 2) == 0) { if ((count % 2) == 0) {
boot_cache_redirect( 0, 64*1024); /* encrypt iv and abstract */
/* encrypt iv and abstruct */
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) { if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
ESP_LOGE(TAG, "encrypt iv and abstract error"); ESP_LOGE(TAG, "encrypt iv and abstract error");
return false; return false;
} }
/* encrypt write boot bin*/ /* encrypt bootloader image */
bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000)); err = esp_image_basic_verify(0x1000, &image_len);
if(bin_len != 0) { if(err == ESP_OK && image_len != 0) {
if (false == flash_encrypt_write(0x1000, bin_len)) { if (false == flash_encrypt_write(0x1000, image_len)) {
ESP_LOGE(TAG, "encrypt 2nd boot error"); ESP_LOGE(TAG, "encrypt 2nd boot error");
return false; return false;
} }
@ -127,6 +130,7 @@ bool flash_encrypt(bootloader_state_t *bs)
ESP_LOGE(TAG, "2nd boot len error"); ESP_LOGE(TAG, "2nd boot len error");
return false; return false;
} }
/* encrypt partition table */ /* encrypt partition table */
if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) { if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
ESP_LOGE(TAG, "encrypt partition table error"); ESP_LOGE(TAG, "encrypt partition table error");
@ -134,48 +138,40 @@ bool flash_encrypt(bootloader_state_t *bs)
} }
/* encrypt write factory bin */ /* encrypt write factory bin */
if(bs->factory.offset != 0x00) { if(bs->factory.offset != 0 && bs->factory.size != 0) {
ESP_LOGD(TAG, "have factory bin"); ESP_LOGD(TAG, "have factory bin");
boot_cache_redirect(bs->factory.offset, bs->factory.size); if (false == flash_encrypt_write(bs->factory.offset, bs->factory.size)) {
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->factory.offset&0xffff));
if(bin_len != 0) {
if (false == flash_encrypt_write(bs->factory.offset, bin_len)) {
ESP_LOGE(TAG, "encrypt factory bin error"); ESP_LOGE(TAG, "encrypt factory bin error");
return false; return false;
} }
} }
}
/* encrypt write test bin */ /* encrypt write test bin */
if(bs->test.offset != 0x00) { if(bs->test.offset != 0 && bs->test.size != 0) {
ESP_LOGD(TAG, "have test bin"); ESP_LOGD(TAG, "have test bin");
boot_cache_redirect(bs->test.offset, bs->test.size); if (false == flash_encrypt_write(bs->test.offset, bs->test.size)) {
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->test.offset&0xffff));
if(bin_len != 0) {
if (false == flash_encrypt_write(bs->test.offset, bin_len)) {
ESP_LOGE(TAG, "encrypt test bin error"); ESP_LOGE(TAG, "encrypt test bin error");
return false; return false;
} }
} }
}
/* encrypt write ota bin */ /* encrypt write ota bin */
for (i = 0;i<16;i++) { for (int i = 0; i < 16; i++) {
if(bs->ota[i].offset != 0x00) { if(bs->ota[i].offset != 0 && bs->ota[i].size != 0) {
ESP_LOGD(TAG, "have ota[%d] bin",i); ESP_LOGD(TAG, "have ota[%d] bin",i);
boot_cache_redirect(bs->ota[i].offset, bs->ota[i].size); if (false == flash_encrypt_write(bs->ota[i].offset, bs->ota[i].size)) {
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->ota[i].offset&0xffff));
if(bin_len != 0) {
if (false == flash_encrypt_write(bs->ota[i].offset, bin_len)) {
ESP_LOGE(TAG, "encrypt ota bin error"); ESP_LOGE(TAG, "encrypt ota bin error");
return false; return false;
} }
} }
} }
}
/* encrypt write ota info bin */ /* encrypt write ota info bin */
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) { if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
ESP_LOGE(TAG, "encrypt ota info error"); ESP_LOGE(TAG, "encrypt ota info error");
return false; return false;
} }
REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04); REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */ REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */ REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */

View file

@ -1,127 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_attr.h"
#include "esp_types.h"
#include "esp_log.h"
#include "rom/cache.h"
#include "rom/ets_sys.h"
#include "rom/spi_flash.h"
#include "rom/secure_boot.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/efuse_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "sdkconfig.h"
#include "bootloader_config.h"
static const char* TAG = "secure_boot";
/**
* @function : secure_boot_generate
* @description: generate boot abstract & iv
*
* @inputs: bool
*/
bool secure_boot_generate(uint32_t bin_len){
SpiFlashOpResult spiRet;
uint16_t i;
uint32_t buf[32];
if (bin_len % 128 != 0) {
bin_len = (bin_len / 128 + 1) * 128;
}
ets_secure_boot_start();
ets_secure_boot_rd_iv(buf);
ets_secure_boot_hash(NULL);
Cache_Read_Disable(0);
/* iv stored in sec 0 */
spiRet = SPIEraseSector(0);
if (spiRet != SPI_FLASH_RESULT_OK)
{
ESP_LOGE(TAG, SPI_ERROR_LOG);
return false;
}
/* write iv to flash, 0x0000, 128 bytes (1024 bits) */
spiRet = SPIWrite(0, buf, 128);
if (spiRet != SPI_FLASH_RESULT_OK)
{
ESP_LOGE(TAG, SPI_ERROR_LOG);
return false;
}
ESP_LOGD(TAG, "write iv to flash.");
Cache_Read_Enable(0);
/* read 4K code image from flash, for test */
for (i = 0; i < bin_len; i+=128) {
ets_secure_boot_hash((uint32_t *)(0x3f400000 + 0x1000 + i));
}
ets_secure_boot_obtain();
ets_secure_boot_rd_abstract(buf);
ets_secure_boot_finish();
Cache_Read_Disable(0);
/* write abstract to flash, 0x0080, 64 bytes (512 bits) */
spiRet = SPIWrite(0x80, buf, 64);
if (spiRet != SPI_FLASH_RESULT_OK) {
ESP_LOGE(TAG, SPI_ERROR_LOG);
return false;
}
ESP_LOGD(TAG, "write abstract to flash.");
Cache_Read_Enable(0);
return true;
}
/**
* @function : secure_boot
* @description: protect boot code in flash
*
* @inputs: bool
*/
bool secure_boot(void){
uint32_t bin_len = 0;
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0)
{
ESP_LOGD(TAG, "already secure boot !");
return true;
} else {
boot_cache_redirect( 0, 64*1024);
bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
if (bin_len == 0) {
ESP_LOGE(TAG, "boot len is error");
return false;
}
if (false == secure_boot_generate(bin_len)){
ESP_LOGE(TAG, "secure boot generate failed");
return false;
}
}
REG_SET_BIT(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_ABS_DONE_0);
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
ESP_LOGW(TAG, "burn abstract_done_0");
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
ESP_LOGI(TAG, "read EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
return true;
}

View file

@ -0,0 +1,9 @@
Bootloader Support Component
============================
Overview
--------
"Bootloader support" contains APIs which are used by the bootloader but are also needed for the main app.
Code in this component needs to be aware of being executed in a bootloader environment (no RTOS available, BOOTLOADER_BUILD macro set) or in an esp-idf app environment (RTOS running, need locking support.)

View file

@ -0,0 +1,35 @@
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := include_priv
ifdef IS_BOOTLOADER_BUILD
# share "private" headers with the bootloader component
# eventual goal: all functionality that needs this lives in bootloader_support
COMPONENT_ADD_INCLUDEDIRS += include_priv
endif
COMPONENT_SRCDIRS := src
#
# Secure boot signing key support
#
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
# this path is created relative to the component build directory
SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)
$(SECURE_BOOT_SIGNING_KEY):
@echo "Need to generate secure boot signing key."
@echo "One way is to run this command:"
@echo "$(ESPSECUREPY) generate_signing_key $@"
@echo "Keep key file safe after generating."
@echo "(See secure boot documentation for risks & alternatives.)"
@exit 1
$(SECURE_BOOT_VERIFICATION_KEY): $(SECURE_BOOT_SIGNING_KEY)
$(ESPSECUREPY) extract_public_key --keyfile $< $@
COMPONENT_EXTRA_CLEAN += $(SECURE_BOOT_VERIFICATION_KEY)
COMPONENT_EMBED_FILES := $(SECURE_BOOT_VERIFICATION_KEY)
endif

View file

@ -0,0 +1,132 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP32_IMAGE_FORMAT_H
#define __ESP32_IMAGE_FORMAT_H
#include <stdbool.h>
#include <esp_err.h>
#define ESP_ERR_IMAGE_BASE 0x2000
#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1)
#define ESP_ERR_IMAGE_INVALID (ESP_ERR_IMAGE_BASE + 2)
/* Support for app/bootloader image parsing
Can be compiled as part of app or bootloader code.
*/
/* SPI flash mode, used in esp_image_header_t */
typedef enum {
ESP_IMAGE_SPI_MODE_QIO,
ESP_IMAGE_SPI_MODE_QOUT,
ESP_IMAGE_SPI_MODE_DIO,
ESP_IMAGE_SPI_MODE_DOUT,
ESP_IMAGE_SPI_MODE_FAST_READ,
ESP_IMAGE_SPI_MODE_SLOW_READ
} esp_image_spi_mode_t;
/* SPI flash clock frequency */
enum {
ESP_IMAGE_SPI_SPEED_40M,
ESP_IMAGE_SPI_SPEED_26M,
ESP_IMAGE_SPI_SPEED_20M,
ESP_IMAGE_SPI_SPEED_80M = 0xF
} esp_image_spi_freq_t;
/* Supported SPI flash sizes */
typedef enum {
ESP_IMAGE_FLASH_SIZE_1MB = 0,
ESP_IMAGE_FLASH_SIZE_2MB,
ESP_IMAGE_FLASH_SIZE_4MB,
ESP_IMAGE_FLASH_SIZE_8MB,
ESP_IMAGE_FLASH_SIZE_16MB,
ESP_IMAGE_FLASH_SIZE_MAX
} esp_image_flash_size_t;
#define ESP_IMAGE_HEADER_MAGIC 0xE9
/* Main header of binary image */
typedef struct {
uint8_t magic;
uint8_t segment_count;
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
uint32_t entry_addr;
uint8_t encrypt_flag; /* encrypt flag */
uint8_t extra_header[15]; /* ESP32 additional header, unused by second bootloader */
} esp_image_header_t;
/* Header of binary image segment */
typedef struct {
uint32_t load_addr;
uint32_t data_len;
} esp_image_segment_header_t;
/**
* @brief Read an ESP image header from flash.
*
* @param src_addr Address in flash to load image header. Must be 4 byte aligned.
* @param[out] image_header Pointer to an esp_image_header_t struture to be filled with data. If the function fails, contents are undefined.
*
* @return ESP_OK if image header was loaded, ESP_ERR_IMAGE_FLASH_FAIL
* if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header
* appears invalid.
*/
esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header);
/**
* @brief Read the segment header and data offset of a segment in the image.
*
* @param index Index of the segment to load information for.
* @param src_addr Base address in flash of the image.
* @param[in] image_header Pointer to the flash image header, already loaded by @ref esp_image_load_header().
* @param[out] segment_header Pointer to a segment header structure to be filled with data. If the function fails, contents are undefined.
* @param[out] segment_data_offset Pointer to the data offset of the segment.
*
* @return ESP_OK if segment_header & segment_data_offset were loaded successfully, ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header appears invalid, ESP_ERR_INVALID_ARG if the index is invalid.
*/
esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset);
/**
* @brief Return length of an image in flash. Non-cryptographically validates image integrity in the process.
*
* If the image has a secure boot signature appended, the signature is not checked and this length is not included in the result.
*
* Image validation checks:
* - Magic byte
* - No single segment longer than 16MB
* - Total image no longer than 16MB
* - 8 bit image checksum is valid
*
* @param src_addr Offset of the start of the image in flash. Must be 4 byte aligned.
* @param[out] length Length of the image, set to a value if the image is valid. Can be null.
*
* @return ESP_OK if image is valid, ESP_FAIL or ESP_ERR_IMAGE_INVALID on errors.
*
*/
esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *length);
typedef struct {
uint32_t drom_addr;
uint32_t drom_load_addr;
uint32_t drom_size;
uint32_t irom_addr;
uint32_t irom_load_addr;
uint32_t irom_size;
} esp_image_flash_mapping_t;
#endif

View file

@ -0,0 +1,75 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP32_SECUREBOOT_H
#define __ESP32_SECUREBOOT_H
#include <stdbool.h>
#include <esp_err.h>
#include "soc/efuse_reg.h"
/* Support functions for secure boot features.
Can be compiled as part of app or bootloader code.
*/
/** @brief Is secure boot currently enabled in hardware?
*
* Secure boot is enabled if the ABS_DONE_0 efuse is blown. This means
* that the ROM bootloader code will only boot a verified secure
* bootloader digest from now on.
*
* @return true if secure boot is enabled.
*/
static inline bool esp_secure_boot_enabled(void) {
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
}
/** @brief Enable secure boot if it is not already enabled.
*
* @important If this function succeeds, secure boot is permanently
* enabled on the chip via efuse.
*
* @important This function is intended to be called from bootloader code only.
*
* If secure boot is not yet enabled for bootloader, this will
* generate the secure boot digest and enable secure boot by blowing
* the EFUSE_RD_ABS_DONE_0 efuse.
*
* This function does not verify secure boot of the bootloader (the
* ROM bootloader does this.)
*
* Will fail if efuses have been part-burned in a way that indicates
* secure boot should not or could not be correctly enabled.
*
*
* @return ESP_ERR_INVALID_STATE if efuse state doesn't allow
* secure boot to be enabled cleanly. ESP_OK if secure boot
* is enabled on this chip from now on.
*/
esp_err_t esp_secure_boot_permanently_enable(void);
/** @brief Verify the secure boot signature (determinstic ECDSA w/ SHA256) appended to some binary data in flash.
*
* Public key is compiled into the calling program. See docs/security/secure-boot.rst for details.
*
* @param src_addr Starting offset of the data in flash.
* @param length Length of data in bytes. Signature is appended -after- length bytes.
*
* @return ESP_OK if signature is valid, ESP_ERR_INVALID_STATE if
* signature fails, ESP_FAIL for other failures (ie can't read flash).
*/
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
#endif

View file

@ -0,0 +1,69 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __BOOTLOADER_FLASH_H
#define __BOOTLOADER_FLASH_H
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <esp_err.h>
/* Provide a Flash API for bootloader_support code,
that can be used from bootloader or app code.
This header is available to source code in the bootloader &
bootloader_support components only.
*/
/**
* @brief Map a region of flash to data memory
*
* @important In bootloader code, only one region can be bootloader_mmaped at once. The previous region must be bootloader_munmapped before another region is mapped.
*
* @important In app code, these functions are not thread safe.
*
* Call bootloader_munmap once for each successful call to bootloader_mmap.
*
* In esp-idf app, this function maps directly to spi_flash_mmap.
*
* @param offset - Starting flash offset to map to memory.
* @param length - Length of data to map.
*
* @return Pointer to mapped data memory (at src_addr), or NULL
* if an allocation error occured.
*/
const void *bootloader_mmap(uint32_t src_addr, uint32_t size);
/**
* @brief Unmap a previously mapped region of flash
*
* Call bootloader_munmap once for each successful call to bootloader_mmap.
*/
void bootloader_munmap(const void *mapping);
/**
* @brief Read data from Flash.
*
* @note Both src and dest have to be 4-byte aligned.
*
* @param src source address of the data in Flash.
* @param dest pointer to the destination buffer
* @param size length of data
*
* @return esp_err_t
*/
esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size);
#endif

View file

@ -0,0 +1,122 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stddef.h>
#include <bootloader_flash.h>
#include <esp_log.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#ifndef BOOTLOADER_BUILD
/* Normal app version maps to esp_spi_flash.h operations...
*/
static const char *TAG = "bootloader_mmap";
static spi_flash_mmap_memory_t map;
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
{
if (map) {
ESP_LOGE(TAG, "tried to bootloader_mmap twice");
return NULL; /* existing mapping in use... */
}
const void *result = NULL;
esp_err_t err = spi_flash_mmap(src_addr, size, SPI_FLASH_MMAP_DATA, &result, &map);
if (err != ESP_OK) {
result = NULL;
}
return result;
}
void bootloader_munmap(const void *mapping)
{
if(mapping && map) {
spi_flash_munmap(map);
}
map = 0;
}
esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size)
{
return spi_flash_read(src, dest, size);
}
#else
/* Bootloader version, uses ROM functions only */
#include <rom/spi_flash.h>
#include <rom/cache.h>
static const char *TAG = "bootloader_flash";
static bool mapped;
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
{
if (mapped) {
ESP_LOGE(TAG, "tried to bootloader_mmap twice");
return NULL; /* can't map twice */
}
uint32_t src_addr_aligned = src_addr & 0xffff0000;
uint32_t count = (size + (src_addr - src_addr_aligned) + 0xffff) / 0x10000;
Cache_Read_Disable(0);
Cache_Flush(0);
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", src_addr_aligned, count );
cache_flash_mmu_set( 0, 0, 0x3f400000, src_addr_aligned, 64, count );
Cache_Read_Enable( 0 );
mapped = true;
return (void *)(0x3f400000 + (src_addr - src_addr_aligned));
}
void bootloader_munmap(const void *mapping)
{
if (mapped) {
/* Full MMU reset */
Cache_Read_Disable(0);
Cache_Flush(0);
mmu_init(0);
mapped = false;
}
}
esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size)
{
if(src_addr & 3) {
ESP_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr);
return ESP_FAIL;
}
if((intptr_t)dest & 3) {
ESP_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest);
return ESP_FAIL;
}
Cache_Read_Disable(0);
Cache_Flush(0);
SpiFlashOpResult r = SPIRead(src_addr, dest, size);
Cache_Read_Enable(0);
switch(r) {
case SPI_FLASH_RESULT_OK:
return ESP_OK;
case SPI_FLASH_RESULT_ERR:
return ESP_ERR_FLASH_OP_FAIL;
case SPI_FLASH_RESULT_TIMEOUT:
return ESP_ERR_FLASH_OP_TIMEOUT;
default:
return ESP_FAIL;
}
}
#endif

View file

@ -0,0 +1,161 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <esp_image_format.h>
#include <esp_log.h>
#include <bootloader_flash.h>
const static char *TAG = "esp_image";
#define SIXTEEN_MB 0x1000000
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header)
{
esp_err_t err;
ESP_LOGD(TAG, "reading image header @ 0x%x", src_addr);
err = bootloader_flash_read(src_addr, image_header, sizeof(esp_image_header_t));
if (err == ESP_OK) {
if (image_header->magic != ESP_IMAGE_HEADER_MAGIC) {
ESP_LOGE(TAG, "image at 0x%x has invalid magic byte", src_addr);
err = ESP_ERR_IMAGE_INVALID;
}
if (image_header->spi_mode > ESP_IMAGE_SPI_MODE_SLOW_READ) {
ESP_LOGW(TAG, "image at 0x%x has invalid SPI mode %d", src_addr, image_header->spi_mode);
}
if (image_header->spi_speed > ESP_IMAGE_SPI_SPEED_80M) {
ESP_LOGW(TAG, "image at 0x%x has invalid SPI speed %d", src_addr, image_header->spi_speed);
}
if (image_header->spi_size > ESP_IMAGE_FLASH_SIZE_MAX) {
ESP_LOGW(TAG, "image at 0x%x has invalid SPI size %d", src_addr, image_header->spi_size);
}
}
if (err != ESP_OK) {
bzero(image_header, sizeof(esp_image_header_t));
}
return err;
}
esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset)
{
esp_err_t err = ESP_OK;
uint32_t next_addr = src_addr + sizeof(esp_image_header_t);
if(index >= image_header->segment_count) {
ESP_LOGE(TAG, "index %d higher than segment count %d", index, image_header->segment_count);
return ESP_ERR_INVALID_ARG;
}
for(int i = 0; i <= index && err == ESP_OK; i++) {
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
err = bootloader_flash_read(next_addr, segment_header, sizeof(esp_image_segment_header_t));
if (err == ESP_OK) {
if ((segment_header->data_len & 3) != 0
|| segment_header->data_len >= SIXTEEN_MB) {
ESP_LOGE(TAG, "invalid segment length 0x%x", segment_header->data_len);
err = ESP_ERR_IMAGE_INVALID;
}
next_addr += sizeof(esp_image_segment_header_t);
ESP_LOGV(TAG, "segment data length 0x%x data starts 0x%x", segment_header->data_len, next_addr);
*segment_data_offset = next_addr;
next_addr += segment_header->data_len;
}
}
if (err != ESP_OK) {
*segment_data_offset = 0;
bzero(segment_header, sizeof(esp_image_segment_header_t));
}
return err;
}
esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *p_length)
{
esp_err_t err;
uint8_t buf[16];
uint8_t checksum = ESP_ROM_CHECKSUM_INITIAL;
esp_image_header_t image_header;
esp_image_segment_header_t segment_header = { 0 };
uint32_t segment_data_offs = 0;
const uint8_t *segment_data;
uint32_t end_addr;
uint32_t length;
if (p_length != NULL) {
*p_length = 0;
}
err = esp_image_load_header(src_addr, &image_header);
if (err != ESP_OK) {
return err;
}
ESP_LOGD(TAG, "reading %d image segments", image_header.segment_count);
/* Checksum each segment's data */
for (int i = 0; i < image_header.segment_count; i++) {
err = esp_image_load_segment_header(i, src_addr, &image_header,
&segment_header, &segment_data_offs);
if (err != ESP_OK) {
return err;
}
segment_data = bootloader_mmap(segment_data_offs, segment_header.data_len);
if (segment_data == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", segment_data_offs, segment_header.data_len);
return ESP_FAIL;
}
for(int i = 0; i < segment_header.data_len; i++) {
checksum ^= segment_data[i];
}
bootloader_munmap(segment_data);
}
/* End of image, verify checksum */
end_addr = segment_data_offs + segment_header.data_len;
if (end_addr < src_addr) {
ESP_LOGE(TAG, "image offset has wrapped");
return ESP_ERR_IMAGE_INVALID;
}
length = end_addr - src_addr;
if (length >= SIXTEEN_MB) {
ESP_LOGE(TAG, "invalid total length 0x%x", length);
return ESP_ERR_IMAGE_INVALID;
}
/* image padded to next full 16 byte block, with checksum byte at very end */
ESP_LOGV(TAG, "unpadded image length 0x%x", length);
length += 16; /* always pad by at least 1 byte */
length = length - (length % 16);
ESP_LOGV(TAG, "padded image length 0x%x", length);
ESP_LOGD(TAG, "reading checksum block at 0x%x", src_addr + length - 16);
bootloader_flash_read(src_addr + length - 16, buf, 16);
if (checksum != buf[15]) {
ESP_LOGE(TAG, "checksum failed. Calculated 0x%x read 0x%x",
checksum, buf[15]);
return ESP_ERR_IMAGE_INVALID;
}
if (p_length != NULL) {
*p_length = length;
}
return ESP_OK;
}

View file

@ -0,0 +1,222 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_attr.h"
#include "esp_types.h"
#include "esp_log.h"
#include "rom/cache.h"
#include "rom/ets_sys.h"
#include "rom/spi_flash.h"
#include "rom/secure_boot.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/efuse_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "sdkconfig.h"
#include "bootloader_flash.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
static const char* TAG = "secure_boot";
#define HASH_BLOCK_SIZE 128
#define IV_LEN HASH_BLOCK_SIZE
#define DIGEST_LEN 64
/**
* @function : secure_boot_generate
* @description: generate boot digest (aka "abstract") & iv
*
* @inputs: image_len - length of image to calculate digest for
*/
static bool secure_boot_generate(uint32_t image_len){
SpiFlashOpResult spiRet;
/* buffer is uint32_t not uint8_t to meet ROM SPI API signature */
uint32_t buf[IV_LEN / sizeof(uint32_t)];
const void *image;
/* hardware secure boot engine only takes full blocks, so round up the
image length. The additional data should all be 0xFF.
*/
if (image_len % HASH_BLOCK_SIZE != 0) {
image_len = (image_len / HASH_BLOCK_SIZE + 1) * HASH_BLOCK_SIZE;
}
ets_secure_boot_start();
ets_secure_boot_rd_iv(buf);
ets_secure_boot_hash(NULL);
Cache_Read_Disable(0);
/* iv stored in sec 0 */
spiRet = SPIEraseSector(0);
if (spiRet != SPI_FLASH_RESULT_OK)
{
ESP_LOGE(TAG, "SPI erase failed %d", spiRet);
return false;
}
Cache_Read_Enable(0);
/* write iv to flash, 0x0000, 128 bytes (1024 bits) */
ESP_LOGD(TAG, "write iv to flash.");
spiRet = SPIWrite(0, buf, IV_LEN);
if (spiRet != SPI_FLASH_RESULT_OK)
{
ESP_LOGE(TAG, "SPI write failed %d", spiRet);
return false;
}
bzero(buf, sizeof(buf));
/* generate digest from image contents */
image = bootloader_mmap(0x1000, image_len);
if (!image) {
ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%x) failed", image_len);
return false;
}
for (int i = 0; i < image_len; i+= HASH_BLOCK_SIZE) {
ets_secure_boot_hash(image + i/sizeof(void *));
}
bootloader_munmap(image);
ets_secure_boot_obtain();
ets_secure_boot_rd_abstract(buf);
ets_secure_boot_finish();
ESP_LOGD(TAG, "write digest to flash.");
spiRet = SPIWrite(0x80, buf, DIGEST_LEN);
if (spiRet != SPI_FLASH_RESULT_OK) {
ESP_LOGE(TAG, "SPI write failed %d", spiRet);
return false;
}
ESP_LOGD(TAG, "write digest to flash.");
Cache_Read_Enable(0);
return true;
}
/* Burn values written to the efuse write registers */
static inline void burn_efuses()
{
#ifdef CONFIG_SECURE_BOOT_TEST_MODE
ESP_LOGE(TAG, "SECURE BOOT TEST MODE. Not really burning any efuses!");
#else
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
#endif
}
esp_err_t esp_secure_boot_permanently_enable(void) {
esp_err_t err;
uint32_t image_len = 0;
if (esp_secure_boot_enabled())
{
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
return ESP_OK;
}
err = esp_image_basic_verify(0x1000, &image_len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
return err;
}
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
if (efuse_key_read_protected == false
&& efuse_key_write_protected == false
&& REG_READ(EFUSE_BLK2_RDATA0_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA1_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA2_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA3_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA4_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA5_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA6_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
ESP_LOGI(TAG, "Generating new secure boot key...");
/* reuse the secure boot IV generation function to generate
the key, as this generator uses the hardware RNG. */
uint32_t buf[32];
ets_secure_boot_start();
ets_secure_boot_rd_iv(buf);
ets_secure_boot_finish();
for (int i = 0; i < 8; i++) {
ESP_LOGV(TAG, "EFUSE_BLK2_WDATA%d_REG = 0x%08x", i, buf[i]);
REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4*i, buf[i]);
}
bzero(buf, sizeof(buf));
burn_efuses();
ESP_LOGI(TAG, "Read & write protecting new key...");
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2);
burn_efuses();
efuse_key_read_protected = true;
efuse_key_write_protected = true;
} else {
ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
}
ESP_LOGI(TAG, "Generating secure boot digest...");
if (false == secure_boot_generate(image_len)){
ESP_LOGE(TAG, "secure boot generation failed");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Digest generation complete.");
if (!efuse_key_read_protected) {
ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
if (!efuse_key_write_protected) {
ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGI(TAG, "blowing secure boot efuse...");
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_0;
#ifdef CONFIG_SECURE_BOOT_DISABLE_JTAG
ESP_LOGI(TAG, "disabling JTAG...");
new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
#endif
#ifdef CONFIG_SECURE_BOOT_DISABLE_UART_BOOTLOADER
ESP_LOGI(TAG, "disabling UART bootloader...");
new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE_S;
#endif
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
burn_efuses();
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
if (after & EFUSE_RD_ABS_DONE_0) {
ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
return ESP_OK;
} else {
#ifdef CONFIG_SECURE_BOOT_TEST_MODE
ESP_LOGE(TAG, "secure boot not enabled due to test mode");
#else
ESP_LOGE(TAG, "secure boot not enabled for bootloader image, EFUSE_RD_ABS_DONE_0 is probably write protected!");
#endif
return ESP_ERR_INVALID_STATE;
}
}

View file

@ -0,0 +1,107 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include "bootloader_flash.h"
#include "esp_log.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "uECC.h"
#ifdef BOOTLOADER_BUILD
#include "rom/sha.h"
typedef SHA_CTX sha_context;
#else
#include "hwcrypto/sha.h"
typedef esp_sha_context sha_context;
#endif
typedef struct {
uint32_t version;
uint8_t signature[64];
} signature_block_t;
static const char* TAG = "secure_boot";
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
#define SIGNATURE_VERIFICATION_KEYLEN 64
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
sha_context sha;
uint8_t digest[32];
ptrdiff_t keylen;
const uint8_t *data, *digest_data;
uint32_t digest_len;
const signature_block_t *sigblock;
bool is_valid;
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
data = bootloader_mmap(src_addr, length + sizeof(signature_block_t));
if(data == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(signature_block_t));
return ESP_FAIL;
}
sigblock = (const signature_block_t *)(data + length);
if (sigblock->version != 0) {
ESP_LOGE(TAG, "src 0x%x has invalid signature version field 0x%08x", src_addr, sigblock->version);
goto unmap_and_fail;
}
#ifdef BOOTLOADER_BUILD
/* Use ROM SHA functions directly */
ets_sha_enable();
ets_sha_init(&sha);
digest_len = length * 8;
digest_data = data;
while (digest_len > 0) {
uint32_t chunk_len = (digest_len > 64) ? 64 : digest_len;
ets_sha_update(&sha, SHA2_256, digest_data, chunk_len);
digest_len -= chunk_len;
digest_data += chunk_len / 8;
}
ets_sha_finish(&sha, SHA2_256, digest);
ets_sha_disable();
#else
/* Use thread-safe esp-idf SHA layer */
esp_sha256_init(&sha);
esp_sha256_start(&sha, false);
esp_sha256_update(&sha, data, length);
esp_sha256_finish(&sha, digest);
esp_sha256_free(&sha);
#endif
keylen = signature_verification_key_end - signature_verification_key_start;
if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
goto unmap_and_fail;
}
is_valid = uECC_verify(signature_verification_key_start,
digest, sizeof(digest), sigblock->signature,
uECC_secp256r1());
bootloader_munmap(data);
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
unmap_and_fail:
bootloader_munmap(data);
return ESP_FAIL;
}

View file

@ -2,20 +2,16 @@
# Component Makefile # Component Makefile
# #
#COMPONENT_ADD_INCLUDEDIRS :=
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses
LIBS := btdm_app LIBS := btdm_app
COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \ COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \
$(addprefix -l,$(LIBS)) \ $(addprefix -l,$(LIBS)) \
$(LINKER_SCRIPTS) $(LINKER_SCRIPTS)
include $(IDF_PATH)/make/component_common.mk
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
$(COMPONENT_LIBRARY): $(ALL_LIB_FILES) $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)

View file

@ -1,14 +1,8 @@
# #
# Component Makefile # Component Makefile
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default,
# this will take the sources in this directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := include/driver COMPONENT_PRIV_INCLUDEDIRS := include/driver
include $(IDF_PATH)/make/component_common.mk

View file

@ -69,6 +69,74 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
GPIO_PIN_REG_39 GPIO_PIN_REG_39
}; };
const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]={
{RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M},
{PERIPHS_IO_MUX_U0TXD_U, FUN_PU, FUN_PD},
{RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M},
{PERIPHS_IO_MUX_U0RXD_U, FUN_PU, FUN_PD},
{RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M},
{PERIPHS_IO_MUX_GPIO5_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_SD_CLK_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_SD_DATA0_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_SD_DATA1_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_SD_DATA2_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_SD_DATA3_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_SD_CMD_U, FUN_PU, FUN_PD},
{RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M},
{RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M},
{RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M},
{RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M},
{PERIPHS_IO_MUX_GPIO16_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO17_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO18_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO19_U, FUN_PU, FUN_PD},
{0,0,0},
{PERIPHS_IO_MUX_GPIO21_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO22_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO23_U, FUN_PU, FUN_PD},
{0,0,0},
{RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M},
{RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M},
{RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M},
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0},
{RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M},
{RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M},
{PERIPHS_IO_MUX_GPIO34_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO35_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO36_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO37_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO38_U, FUN_PU, FUN_PD},
{PERIPHS_IO_MUX_GPIO39_U, FUN_PU, FUN_PD}
};
esp_err_t gpio_pullup_en(gpio_num_t gpio_num) {
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
return ESP_OK;
}
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) {
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
return ESP_OK;
}
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) {
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
return ESP_OK;
}
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) {
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
return ESP_OK;
}
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type) esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
{ {
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
@ -152,20 +220,20 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
switch(pull) { switch(pull) {
case GPIO_PULLUP_ONLY: case GPIO_PULLUP_ONLY:
PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]); REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]); REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
break; break;
case GPIO_PULLDOWN_ONLY: case GPIO_PULLDOWN_ONLY:
PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]); REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]); REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
break; break;
case GPIO_PULLUP_PULLDOWN: case GPIO_PULLUP_PULLDOWN:
PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]); REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]); REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
break; break;
case GPIO_FLOATING: case GPIO_FLOATING:
PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]); REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]); REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
break; break;
default: default:
ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u",gpio_num,pull); ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u",gpio_num,pull);
@ -253,15 +321,15 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
} }
if(pGPIOConfig->pull_up_en) { if(pGPIOConfig->pull_up_en) {
pu_en = 1; pu_en = 1;
PIN_PULLUP_EN(io_reg); REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
} else { } else {
PIN_PULLUP_DIS(io_reg); REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
} }
if(pGPIOConfig->pull_down_en) { if(pGPIOConfig->pull_down_en) {
pd_en = 1; pd_en = 1;
PIN_PULLDWN_EN(io_reg); REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
} else { } else {
PIN_PULLDWN_DIS(io_reg); REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
} }
ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, pGPIOConfig->intr_type); ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, pGPIOConfig->intr_type);
gpio_set_intr_type(io_num, pGPIOConfig->intr_type); gpio_set_intr_type(io_num, pGPIOConfig->intr_type);

View file

@ -117,6 +117,29 @@ extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT];
#define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0)) //to decide whether it is a valid GPIO number #define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0)) //to decide whether it is a valid GPIO number
#define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34)) //to decide whether it can be a valid GPIO number of output mode #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34)) //to decide whether it can be a valid GPIO number of output mode
typedef struct {
uint32_t reg; /*!< Register to modify to enable or disable pullups or pulldowns */
uint32_t pu; /*!< Bit to set or clear in the above register to enable or disable the pullup, respectively */
uint32_t pd; /*!< Bit to set or clear in the above register to enable or disable the pulldown, respectively */
} gpio_pu_pd_desc_t;
/**
* Per-GPIO pullup/pulldown information
* On the ESP32, some GPIOs need their pullups and pulldowns enabled and disabled in the RTC
* peripheral instead of in the GPIO peripheral. This array documents for every GPIO what bit
* to set or clear.
*
* This array is non-static, so if you need a very quick way of toggling the pull-up/downs, you can just
* do e.g. REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); inline.
*
* ToDo: Functions using the contents of this array will do a read/modify/write on GPIO as well as RTC
* registers. We may need to look into muxes/locks for other code that accesses these RTC registers when we
* write drivers for the RTC stuff.
*/
extern const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT];
typedef enum { typedef enum {
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
@ -220,7 +243,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig);
/** /**
* @brief GPIO set interrupt trigger type * @brief GPIO set interrupt trigger type
* *
* @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param intr_type Interrupt type, select from gpio_int_type_t * @param intr_type Interrupt type, select from gpio_int_type_t
* *
* @return * @return
@ -233,7 +256,7 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/** /**
* @brief Enable GPIO module interrupt signal * @brief Enable GPIO module interrupt signal
* *
* @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* *
* @return * @return
* - ESP_OK Success * - ESP_OK Success
@ -245,7 +268,7 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num);
/** /**
* @brief Disable GPIO module interrupt signal * @brief Disable GPIO module interrupt signal
* *
* @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* *
* @return * @return
* - ESP_OK success * - ESP_OK success
@ -257,7 +280,7 @@ esp_err_t gpio_intr_disable(gpio_num_t gpio_num);
/** /**
* @brief GPIO set output level * @brief GPIO set output level
* *
* @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param level Output level. 0: low ; 1: high * @param level Output level. 0: low ; 1: high
* *
* @return * @return
@ -270,7 +293,7 @@ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
/** /**
* @brief GPIO get input level * @brief GPIO get input level
* *
* @param gpio_num GPIO number. If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
* *
* @return * @return
* - 0 the GPIO input level is 0 * - 0 the GPIO input level is 0
@ -284,7 +307,7 @@ int gpio_get_level(gpio_num_t gpio_num);
* *
* Configure GPIO direction,such as output_only,input_only,output_and_input * Configure GPIO direction,such as output_only,input_only,output_and_input
* *
* @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param mode GPIO direction * @param mode GPIO direction
* *
* @return * @return
@ -299,7 +322,7 @@ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
* *
* User this Function,configure GPIO pull mode,such as pull-up,pull-down * User this Function,configure GPIO pull mode,such as pull-up,pull-down
* *
* @param gpio_num GPIO number. If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16); * @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param pull GPIO pull up/down mode. * @param pull GPIO pull up/down mode.
* *
* @return * @return
@ -354,6 +377,53 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
*/ */
esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg); esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg);
/**
* @brief Enable pull-up on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pullup_en(gpio_num_t gpio_num);
/**
* @brief Disable pull-up on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num);
/**
* @brief Enable pull-down on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);
/**
* @brief Disable pull-down on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
/** /**
* *************** ATTENTION ********************/ * *************** ATTENTION ********************/
/** /**

View file

@ -1,28 +1,20 @@
# #
# Component Makefile # Component Makefile
# #
# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default,
# this will take the sources in this directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the esp-idf build system document if you need to do this.
#
-include include/config/auto.conf
COMPONENT_SRCDIRS := . hwcrypto COMPONENT_SRCDIRS := . hwcrypto
LIBS := core net80211 phy rtc pp wpa smartconfig coexist LIBS := core net80211 phy rtc pp wpa smartconfig coexist wps
LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
COMPONENT_ADD_LDFLAGS := -lesp32 \ COMPONENT_ADD_LDFLAGS := -lesp32 \
$(abspath libhal.a) \ $(COMPONENT_PATH)/libhal.a \
-L$(abspath lib) \ -L$(COMPONENT_PATH)/lib \
$(addprefix -l,$(LIBS)) \ $(addprefix -l,$(LIBS)) \
-L $(abspath ld) \ -L $(COMPONENT_PATH)/ld \
$(LINKER_SCRIPTS) $(LINKER_SCRIPTS)
include $(IDF_PATH)/make/component_common.mk
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
# automatically trigger a git submodule update # automatically trigger a git submodule update
@ -44,8 +36,6 @@ $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
# saves us from having to add the target to a Makefile.projbuild # saves us from having to add the target to a Makefile.projbuild
$(COMPONENT_LIBRARY): esp32_out.ld $(COMPONENT_LIBRARY): esp32_out.ld
# .. is BUILD_DIR_BASE here, as component makefiles
# are evaluated with CWD=component build dir
esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h
$(CC) -I ../include -C -P -x c -E $< -o $@ $(CC) -I ../include -C -P -x c -E $< -o $@

View file

@ -68,6 +68,10 @@ static system_event_handle_t g_system_event_handle_table[] = {
{SYSTEM_EVENT_STA_DISCONNECTED, system_event_sta_disconnected_handle_default}, {SYSTEM_EVENT_STA_DISCONNECTED, system_event_sta_disconnected_handle_default},
{SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL}, {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
{SYSTEM_EVENT_STA_GOT_IP, system_event_sta_got_ip_default}, {SYSTEM_EVENT_STA_GOT_IP, system_event_sta_got_ip_default},
{SYSTEM_EVENT_STA_WPS_ER_SUCCESS, NULL},
{SYSTEM_EVENT_STA_WPS_ER_FAILED, NULL},
{SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, NULL},
{SYSTEM_EVENT_STA_WPS_ER_PIN, NULL},
{SYSTEM_EVENT_AP_START, system_event_ap_start_handle_default}, {SYSTEM_EVENT_AP_START, system_event_ap_start_handle_default},
{SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default}, {SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default},
{SYSTEM_EVENT_AP_STACONNECTED, NULL}, {SYSTEM_EVENT_AP_STACONNECTED, NULL},
@ -220,6 +224,22 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
IP2STR(&got_ip->ip_info.gw)); IP2STR(&got_ip->ip_info.gw));
break; break;
} }
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: {
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS");
break;
}
case SYSTEM_EVENT_STA_WPS_ER_FAILED: {
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_FAILED");
break;
}
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: {
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_TIMEOUT");
break;
}
case SYSTEM_EVENT_STA_WPS_ER_PIN: {
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN");
break;
}
case SYSTEM_EVENT_AP_START: { case SYSTEM_EVENT_AP_START: {
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START"); ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
break; break;

View file

@ -0,0 +1,96 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "esp_freertos_hooks.h"
//We use just a static array here because it's not expected many components will need
//an idle or tick hook.
#define MAX_HOOKS 8
static esp_freertos_idle_cb_t idle_cb[MAX_HOOKS]={0};
static esp_freertos_tick_cb_t tick_cb[MAX_HOOKS]={0};
void IRAM_ATTR esp_vApplicationTickHook()
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (tick_cb[n]!=NULL) {
tick_cb[n]();
}
}
}
void esp_vApplicationIdleHook()
{
bool doWait=true;
bool r;
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (idle_cb[n]!=NULL) {
r=idle_cb[n]();
if (!r) doWait=false;
}
}
if (doWait) {
//Wait for whatever interrupt comes next... this should save some power.
asm("waiti 0");
}
}
esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (idle_cb[n]==NULL) {
idle_cb[n]=new_idle_cb;
return ESP_OK;
}
}
return ESP_ERR_NO_MEM;
}
esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (tick_cb[n]==NULL) {
tick_cb[n]=new_tick_cb;
return ESP_OK;
}
}
return ESP_ERR_NO_MEM;
}
void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (idle_cb[n]==old_idle_cb) idle_cb[n]=NULL;
}
}
void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (tick_cb[n]==old_tick_cb) tick_cb[n]=NULL;
}
}

View file

@ -25,6 +25,7 @@
#include "soc/io_mux_reg.h" #include "soc/io_mux_reg.h"
#include "esp_gdbstub.h" #include "esp_gdbstub.h"
#include "driver/gpio.h"
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which //Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
//implies a minimum size of about 320 bytes. //implies a minimum size of about 320 bytes.
@ -354,7 +355,7 @@ static int gdbReadCommand() {
void esp_gdbstub_panic_handler(XtExcFrame *frame) { void esp_gdbstub_panic_handler(XtExcFrame *frame) {
dumpHwToRegfile(frame); dumpHwToRegfile(frame);
//Make sure txd/rxd are enabled //Make sure txd/rxd are enabled
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); gpio_pullup_dis(1);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);

View file

@ -35,6 +35,10 @@ typedef enum {
SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */ SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
SYSTEM_EVENT_STA_GOT_IP, /**< ESP32 station got IP from connected AP */ SYSTEM_EVENT_STA_GOT_IP, /**< ESP32 station got IP from connected AP */
SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
SYSTEM_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
SYSTEM_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
SYSTEM_EVENT_AP_START, /**< ESP32 soft-AP start */ SYSTEM_EVENT_AP_START, /**< ESP32 soft-AP start */
SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */ SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
@ -73,6 +77,10 @@ typedef struct {
tcpip_adapter_ip_info_t ip_info; tcpip_adapter_ip_info_t ip_info;
} system_event_sta_got_ip_t; } system_event_sta_got_ip_t;
typedef struct {
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
}system_event_sta_wps_er_pin_t;
typedef struct { typedef struct {
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */ uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */ uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
@ -94,6 +102,7 @@ typedef union {
system_event_sta_scan_done_t scan_done; /**< ESP32 station scan (APs) done */ system_event_sta_scan_done_t scan_done; /**< ESP32 station scan (APs) done */
system_event_sta_authmode_change_t auth_change; /**< the auth mode of AP ESP32 station connected to changed */ system_event_sta_authmode_change_t auth_change; /**< the auth mode of AP ESP32 station connected to changed */
system_event_sta_got_ip_t got_ip; /**< ESP32 station got IP */ system_event_sta_got_ip_t got_ip; /**< ESP32 station got IP */
system_event_sta_wps_er_pin_t sta_er_pin; /**< ESP32 station WPS enrollee mode PIN code received */
system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */ system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */
system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */ system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */
system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */ system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */

View file

@ -21,57 +21,9 @@ extern "C"
{ {
#endif #endif
#define ESP_PARTITION_TABLE_ADDR 0x4000 #define ESP_PARTITION_TABLE_ADDR 0x8000
#define ESP_PARTITION_MAGIC 0x50AA #define ESP_PARTITION_MAGIC 0x50AA
/* SPI flash mode, used in esp_image_header_t */
typedef enum {
ESP_IMAGE_SPI_MODE_QIO,
ESP_IMAGE_SPI_MODE_QOUT,
ESP_IMAGE_SPI_MODE_DIO,
ESP_IMAGE_SPI_MODE_DOUT,
ESP_IMAGE_SPI_MODE_FAST_READ,
ESP_IMAGE_SPI_MODE_SLOW_READ
} esp_image_spi_mode_t;
/* SPI flash clock frequency */
enum {
ESP_IMAGE_SPI_SPEED_40M,
ESP_IMAGE_SPI_SPEED_26M,
ESP_IMAGE_SPI_SPEED_20M,
ESP_IMAGE_SPI_SPEED_80M = 0xF
} esp_image_spi_freq_t;
/* Supported SPI flash sizes */
typedef enum {
ESP_IMAGE_FLASH_SIZE_1MB = 0,
ESP_IMAGE_FLASH_SIZE_2MB,
ESP_IMAGE_FLASH_SIZE_4MB,
ESP_IMAGE_FLASH_SIZE_8MB,
ESP_IMAGE_FLASH_SIZE_16MB,
ESP_IMAGE_FLASH_SIZE_MAX
} esp_image_flash_size_t;
/* Main header of binary image */
typedef struct {
uint8_t magic;
uint8_t blocks;
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
uint32_t entry_addr;
uint8_t encrypt_flag; /* encrypt flag */
uint8_t secure_boot_flag; /* secure boot flag */
uint8_t extra_header[14]; /* ESP32 additional header, unused by second bootloader */
} esp_image_header_t;
/* Header of binary image segment */
typedef struct {
uint32_t load_addr;
uint32_t data_len;
} esp_image_section_header_t;
/* OTA selection structure (two copies in the OTA data partition.) /* OTA selection structure (two copies in the OTA data partition.)
Size of 32 bytes is friendly to flash encryption */ Size of 32 bytes is friendly to flash encryption */
typedef struct { typedef struct {

View file

@ -0,0 +1,83 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_FREERTOS_HOOKS_H__
#define __ESP_FREERTOS_HOOKS_H__
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*
Definitions for the tickhook and idlehook callbacks
*/
typedef bool (*esp_freertos_idle_cb_t)();
typedef void (*esp_freertos_tick_cb_t)();
/**
* @brief Register a callback to be called on the freertos idle hook
* The callback should return true if it's okay for the core to
* sleep until an interrupt (or FreeRTOS tick) happens and false
* if it should be called again as fast as possible.
*
* @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL
* A FUNCTION THAT MIGHT BLOCK.
*
* @param esp_freertos_idle_cb_t new_idle_cb : Callback to be called
*
* @return ESP_OK : Callback registered
* @return ESP_ERR_NO_MEM : No more space to register hook
*/
esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb);
/**
* @brief Register a callback to be called on the freertos tick hook
*
* @param esp_freertos_tick_cb_t new_tick_cb : Callback to be called
*
* @return ESP_OK : Callback registered
* @return ESP_ERR_NO_MEM : No more space to register hook
*/
esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t tick_cb);
/**
* @brief Unregister an idle callback registered earlier
*
* @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered
*
* @return void
*/
void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb);
/**
* @brief Unregister a tick callback registered earlier
*
* @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered
*
* @return void
*/
void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,111 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_WPS_H__
#define __ESP_WPS_H__
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup WiFi_APIs WiFi Related APIs
* @brief WiFi APIs
*/
/** @addtogroup WiFi_APIs
* @{
*/
/** \defgroup WPS_APIs WPS APIs
* @brief ESP32 WPS APIs
*
* WPS can only be used when ESP32 station is enabled.
*
*/
/** @addtogroup WPS_APIs
* @{
*/
#define ESP_ERR_WIFI_REGISTRAR (ESP_ERR_WIFI_BASE + 51) /*!< WPS registrar is not supported */
#define ESP_ERR_WIFI_WPS_TYPE (ESP_ERR_WIFI_BASE + 52) /*!< WPS type error */
#define ESP_ERR_WIFI_WPS_SM (ESP_ERR_WIFI_BASE + 53) /*!< WPS state machine is not initialized */
typedef enum wps_type {
WPS_TYPE_DISABLE = 0,
WPS_TYPE_PBC,
WPS_TYPE_PIN,
WPS_TYPE_MAX,
} wps_type_t;
/**
* @brief Enable Wi-Fi WPS function.
*
* @attention WPS can only be used when ESP32 station is enabled.
*
* @param wps_type_t wps_type : WPS type, so far only WPS_TYPE_PBC and WPS_TYPE_PIN is supported
*
* @return
* - ESP_OK : succeed
* - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid
* - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
* - ESP_ERR_WIFI_FAIL : wps initialization fails
*/
esp_err_t esp_wifi_wps_enable(wps_type_t wps_type);
/**
* @brief Disable Wi-Fi WPS function and release resource it taken.
*
* @param null
*
* @return
* - ESP_OK : succeed
* - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
*/
esp_err_t esp_wifi_wps_disable(void);
/**
* @brief WPS starts to work.
*
* @attention WPS can only be used when ESP32 station is enabled.
*
* @param timeout_ms : maximum blocking time before API return.
* - 0 : non-blocking
* - 1~120000 : blocking time (not supported in IDF v1.0)
*
* @return
* - ESP_OK : succeed
* - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid
* - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
* - ESP_ERR_WIFI_WPS_SM : wps state machine is not initialized
* - ESP_ERR_WIFI_FAIL : wps initialization fails
*/
esp_err_t esp_wifi_wps_start(int timeout_ms);
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ESP_WPS_H__ */

View file

@ -25,7 +25,7 @@ void ets_secure_boot_start(void);
void ets_secure_boot_finish(void); void ets_secure_boot_finish(void);
void ets_secure_boot_hash(uint32_t *buf); void ets_secure_boot_hash(const uint32_t *buf);
void ets_secure_boot_obtain(void); void ets_secure_boot_obtain(void);

View file

@ -29,6 +29,16 @@
#define EFUSE_RD_EFUSE_RD_DIS_M ((EFUSE_RD_EFUSE_RD_DIS_V)<<(EFUSE_RD_EFUSE_RD_DIS_S)) #define EFUSE_RD_EFUSE_RD_DIS_M ((EFUSE_RD_EFUSE_RD_DIS_V)<<(EFUSE_RD_EFUSE_RD_DIS_S))
#define EFUSE_RD_EFUSE_RD_DIS_V 0xF #define EFUSE_RD_EFUSE_RD_DIS_V 0xF
#define EFUSE_RD_EFUSE_RD_DIS_S 16 #define EFUSE_RD_EFUSE_RD_DIS_S 16
/* Read disable bits for efuse blocks 1-3 */
#define EFUSE_RD_DIS_BLK1 (1<<16)
#define EFUSE_RD_DIS_BLK2 (1<<17)
#define EFUSE_RD_DIS_BLK3 (1<<18)
/* Read disable FLASH_CRYPT_CONFIG, CODING_SCHEME & KEY_STATUS
in efuse block 0
*/
#define EFUSE_RD_DIS_BLK0_PARTIAL (1<<19)
/* EFUSE_RD_EFUSE_WR_DIS : RO ;bitpos:[15:0] ;default: 16'b0 ; */ /* EFUSE_RD_EFUSE_WR_DIS : RO ;bitpos:[15:0] ;default: 16'b0 ; */
/*description: read for efuse_wr_disable*/ /*description: read for efuse_wr_disable*/
#define EFUSE_RD_EFUSE_WR_DIS 0x0000FFFF #define EFUSE_RD_EFUSE_WR_DIS 0x0000FFFF
@ -36,6 +46,22 @@
#define EFUSE_RD_EFUSE_WR_DIS_V 0xFFFF #define EFUSE_RD_EFUSE_WR_DIS_V 0xFFFF
#define EFUSE_RD_EFUSE_WR_DIS_S 0 #define EFUSE_RD_EFUSE_WR_DIS_S 0
/* Write disable bits */
#define EFUSE_WR_DIS_RD_DIS (1<<0) /*< disable writing read disable reg */
#define EFUSE_WR_DIS_WR_DIS (1<<1) /*< disable writing write disable reg */
#define EFUSE_WR_DIS_FLASH_CRYPT_CNT (1<<2)
#define EFUSE_WR_DIS_MAC_SPI_CONFIG_HD (1<<3) /*< disable writing MAC & SPI config hd efuses */
#define EFUSE_WR_DIS_XPD_SDIO (1<<5) /*< disable writing SDIO config efuses */
#define EFUSE_WR_DIS_SPI_PAD_CONFIG (1<<6) /*< disable writing SPI_PAD_CONFIG efuses */
#define EFUSE_WR_DIS_BLK1 (1<<7) /*< disable writing BLK1 efuses */
#define EFUSE_WR_DIS_BLK2 (1<<8) /*< disable writing BLK2 efuses */
#define EFUSE_WR_DIS_BLK3 (1<<9) /*< disable writing BLK3 efuses */
#define EFUSE_WR_DIS_FLASH_CRYPT_CODING_SCHEME (1<<10) /*< disable writing FLASH_CRYPT_CONFIG and CODING_SCHEME efuses */
#define EFUSE_WR_DIS_ABS_DONE_0 (1<<12) /*< disable writing ABS_DONE_0 efuse */
#define EFUSE_WR_DIS_ABS_DONE_1 (1<<13) /*< disable writing ABS_DONE_1 efuse */
#define EFUSE_WR_DIS_JTAG_DISABLE (1<<14) /*< disable writing JTAG_DISABLE efuse */
#define EFUSE_WR_DIS_CONSOLE_DL_DISABLE (1<<15) /*< disable writing CONSOLE_DEBUG_DISABLE, DISABLE_DL_ENCRYPT, DISABLE_DL_DECRYPT and DISABLE_DL_CACHE efuses */
#define EFUSE_BLK0_RDATA1_REG (DR_REG_EFUSE_BASE + 0x004) #define EFUSE_BLK0_RDATA1_REG (DR_REG_EFUSE_BASE + 0x004)
/* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */ /* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */
/*description: read for low 32bit WIFI_MAC_Address*/ /*description: read for low 32bit WIFI_MAC_Address*/

View file

@ -34,10 +34,41 @@
#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) #define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) #define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); #define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv));
#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU)
#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) /*
#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) * @attention
#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) * The PIN_PULL[UP|DWN]_[EN|DIS]() functions used to exist as macros in previous SDK versions.
* Unfortunately, however, they do not work for some GPIOs on the ESP32 chip, which needs pullups
* and -downs turned on and off through RTC registers. The functions still exist for compatibility
* with older code, but are marked as deprecated in order to generate a warning.
* Please replace them in this fashion: (make sure to include driver/gpio.h as well)
* PIN_PULLUP_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_en(x)
* PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_dis(x)
* PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_en(x)
* PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_dis(x)
*
*/
static inline void __attribute__ ((deprecated)) PIN_PULLUP_DIS(uint32_t PIN_NAME)
{
REG_CLR_BIT(PIN_NAME, FUN_PU);
}
static inline void __attribute__ ((deprecated)) PIN_PULLUP_EN(uint32_t PIN_NAME)
{
REG_SET_BIT(PIN_NAME, FUN_PU);
}
static inline void __attribute__ ((deprecated)) PIN_PULLDWN_DIS(uint32_t PIN_NAME)
{
REG_CLR_BIT(PIN_NAME, FUN_PD);
}
static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME)
{
REG_SET_BIT(PIN_NAME, FUN_PD);
}
#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) #define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC)
#define PIN_FUNC_GPIO 2 #define PIN_FUNC_GPIO 2

View file

@ -25,6 +25,7 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_intr.h" #include "esp_intr.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_freertos_hooks.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
@ -36,6 +37,38 @@
#define WDT_INT_NUM 24 #define WDT_INT_NUM 24
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
#if CONFIG_INT_WDT_CHECK_CPU1
//Not static; the ISR assembly checks this.
bool int_wdt_app_cpu_ticked=false;
static void IRAM_ATTR tick_hook(void) {
if (xPortGetCoreID()!=0) {
int_wdt_app_cpu_ticked=true;
} else {
//Only feed wdt if app cpu also ticked.
if (int_wdt_app_cpu_ticked) {
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
int_wdt_app_cpu_ticked=false;
}
}
}
#else
static void IRAM_ATTR tick_hook(void) {
if (xPortGetCoreID()!=0) return;
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
}
#endif
void esp_int_wdt_init() { void esp_int_wdt_init() {
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS
@ -53,6 +86,7 @@ void esp_int_wdt_init() {
TIMERG1.wdt_wprotect=0; TIMERG1.wdt_wprotect=0;
TIMERG1.int_clr_timers.wdt=1; TIMERG1.int_clr_timers.wdt=1;
TIMERG1.int_ena.wdt=1; TIMERG1.int_ena.wdt=1;
esp_register_freertos_tick_hook(tick_hook);
ESP_INTR_DISABLE(WDT_INT_NUM); ESP_INTR_DISABLE(WDT_INT_NUM);
intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
//We do not register a handler for the interrupt because it is interrupt level 4 which //We do not register a handler for the interrupt because it is interrupt level 4 which
@ -62,35 +96,5 @@ void esp_int_wdt_init() {
} }
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
#if CONFIG_INT_WDT_CHECK_CPU1
//Not static; the ISR assembly checks this.
bool int_wdt_app_cpu_ticked=false;
void IRAM_ATTR vApplicationTickHook(void) {
if (xPortGetCoreID()!=0) {
int_wdt_app_cpu_ticked=true;
} else {
//Only feed wdt if app cpu also ticked.
if (int_wdt_app_cpu_ticked) {
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
int_wdt_app_cpu_ticked=false;
}
}
}
#else
void IRAM_ATTR vApplicationTickHook(void) {
if (xPortGetCoreID()!=0) return;
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
}
#endif
#endif #endif

@ -1 +1 @@
Subproject commit 84af0ed366e1ba38984f7df517a77f8ec4fa27ed Subproject commit 01f5c068e1ac3968add98439ee2f1748b9e391fa

View file

@ -26,6 +26,7 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_intr.h" #include "esp_intr.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_freertos_hooks.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
#include "esp_log.h" #include "esp_log.h"
@ -140,6 +141,18 @@ void esp_task_wdt_delete() {
} }
} }
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
static bool idle_hook(void) {
#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
if (xPortGetCoreID()!=0) return true;
#endif
esp_task_wdt_feed();
return true;
}
#endif
void esp_task_wdt_init() { void esp_task_wdt_init() {
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
@ -153,6 +166,9 @@ void esp_task_wdt_init() {
TIMERG0.wdt_config0.en=1; TIMERG0.wdt_config0.en=1;
TIMERG0.wdt_feed=1; TIMERG0.wdt_feed=1;
TIMERG0.wdt_wprotect=0; TIMERG0.wdt_wprotect=0;
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
esp_register_freertos_idle_hook(idle_hook);
#endif
ESP_INTR_DISABLE(ETS_T0_WDT_INUM); ESP_INTR_DISABLE(ETS_T0_WDT_INUM);
intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM); intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL); xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
@ -161,13 +177,5 @@ void esp_task_wdt_init() {
ESP_INTR_ENABLE(ETS_T0_WDT_INUM); ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
} }
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
void vApplicationIdleHook(void) {
#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
if (xPortGetCoreID()!=0) return;
#endif
esp_task_wdt_feed();
}
#endif
#endif #endif

View file

@ -11,27 +11,47 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
# two commands that can be used from other components # two commands that can be used from other components
# to invoke esptool.py (with or without serial port args) # to invoke esptool.py (with or without serial port args)
# #
# NB: esptool.py lives in the sdk/bin directory not the component directory
ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32 ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
# Supporting esptool command line tools
ESPEFUSEPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espefuse.py
ESPSECUREPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espsecure.py
export ESPSECUREPY # is used in bootloader_support component
ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE) ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE)
# the no-stub argument is temporary until esptool.py fully supports compressed uploads ESPTOOL_ELF2IMAGE_OPTIONS :=
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS) ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS)
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC) ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
$(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $< ifndef IS_BOOTLOADER_BUILD
# for secure boot, add a signing step to get from unsiged app to signed app
APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin)
$(APP_BIN): $(APP_BIN_UNSIGNED)
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $^ # signed in-place
endif
endif
# non-secure boot (or bootloader), both these files are the same
APP_BIN_UNSIGNED ?= $(APP_BIN)
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC)
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
flash: all_binaries $(ESPTOOLPY_SRC) flash: all_binaries $(ESPTOOLPY_SRC)
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."
$(Q) $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
endif
$(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) app-flash: $(APP_BIN) $(ESPTOOLPY_SRC)
@echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..." @echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..."
$(Q) $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN)
$(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool)) $(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool))

@ -1 +1 @@
Subproject commit 5c6962e894e0a118c9a4b5760876433493449260 Subproject commit b1e00025fa6cbc63062b205259ee70d91bfe4989

View file

@ -1,15 +1,9 @@
# #
# Component Makefile # Component Makefile
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
# this will take the sources in this directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := port/include include/expat COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
COMPONENT_SRCDIRS := library port COMPONENT_SRCDIRS := library port
CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
include $(IDF_PATH)/make/component_common.mk

View file

@ -141,6 +141,35 @@ config FREERTOS_ISR_STACKSIZE
The interrupt handlers have their own stack. The size of the stack can be defined here. The interrupt handlers have their own stack. The size of the stack can be defined here.
Each processor has its own stack, so the total size occupied will be twice this. Each processor has its own stack, so the total size occupied will be twice this.
config FREERTOS_LEGACY_HOOKS
bool "Use FreeRTOS legacy hooks"
default n
help
FreeRTOS offers a number of hooks/callback functions that are called when a timer
tick happens, the idle thread runs etc. esp-idf replaces these by runtime registerable
hooks using the esp_register_freertos_xxx_hook system, but for legacy reasons the old
hooks can also still be enabled. Please enable this only if you have code that for some
reason can't be migrated to the esp_register_freertos_xxx_hook system.
if FREERTOS_LEGACY_HOOKS
config FREERTOS_LEGACY_IDLE_HOOK
bool "Enable legacy idle hook"
default n
help
If enabled, FreeRTOS will call a function called vApplicationIdleHook when the idle thread
on a CPU is running. Please make sure your code defines such a function.
config FREERTOS_LEGACY_TICK_HOOK
bool "Enable legacy tick hook"
default n
help
If enabled, FreeRTOS will call a function called vApplicationTickHook when a FreeRTOS
tick is executed. Please make sure your code defines such a function.
endif #FREERTOS_LEGACY_HOOKS
menuconfig FREERTOS_DEBUG_INTERNALS menuconfig FREERTOS_DEBUG_INTERNALS
bool "Debug FreeRTOS internals" bool "Debug FreeRTOS internals"
default n default n

View file

@ -6,4 +6,3 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := include/freertos COMPONENT_PRIV_INCLUDEDIRS := include/freertos
include $(IDF_PATH)/make/component_common.mk

View file

@ -152,9 +152,9 @@
*----------------------------------------------------------*/ *----------------------------------------------------------*/
#define configUSE_PREEMPTION 1 #define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK ( CONFIG_TASK_WDT_CHECK_IDLE_TASK ) #define configUSE_IDLE_HOOK ( CONFIG_FREERTOS_LEGACY_IDLE_HOOK )
#define configUSE_TICK_HOOK ( CONFIG_INT_WDT ) #define configUSE_TICK_HOOK ( CONFIG_FREERTOS_LEGACY_TICK_HOOK )
#define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ ) #define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ )

View file

@ -476,6 +476,7 @@ to its original value when it is released. */
#if configUSE_TICK_HOOK > 0 #if configUSE_TICK_HOOK > 0
extern void vApplicationTickHook( void ); extern void vApplicationTickHook( void );
#endif #endif
extern void esp_vApplicationTickHook( void );
#if portFIRST_TASK_HOOK #if portFIRST_TASK_HOOK
extern void vPortFirstTaskHook(TaskFunction_t taskfn); extern void vPortFirstTaskHook(TaskFunction_t taskfn);
@ -2360,22 +2361,21 @@ BaseType_t xSwitchRequired = pdFALSE;
We can't really calculate what we need, that's done on core 0... just assume we need a switch. We can't really calculate what we need, that's done on core 0... just assume we need a switch.
ToDo: Make this more intelligent? -- JD ToDo: Make this more intelligent? -- JD
*/ */
//We do need the tick hook to satisfy the int watchdog.
#if ( configUSE_TICK_HOOK == 1 )
{ {
/* Guard against the tick hook being called when the pended tick /* Guard against the tick hook being called when the pended tick
count is being unwound (when the scheduler is being unlocked). */ count is being unwound (when the scheduler is being unlocked). */
if( ( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) || uxPendedTicks == ( UBaseType_t ) 0U ) if( ( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) || uxPendedTicks == ( UBaseType_t ) 0U )
{ {
#if ( configUSE_TICK_HOOK == 1 )
vApplicationTickHook(); vApplicationTickHook();
#endif /* configUSE_TICK_HOOK */
esp_vApplicationTickHook();
} }
else else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
#endif /* configUSE_TICK_HOOK */
return pdTRUE; return pdTRUE;
} }
@ -2506,20 +2506,21 @@ BaseType_t xSwitchRequired = pdFALSE;
} }
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
#if ( configUSE_TICK_HOOK == 1 )
{ {
/* Guard against the tick hook being called when the pended tick /* Guard against the tick hook being called when the pended tick
count is being unwound (when the scheduler is being unlocked). */ count is being unwound (when the scheduler is being unlocked). */
if( uxPendedTicks == ( UBaseType_t ) 0U ) if( uxPendedTicks == ( UBaseType_t ) 0U )
{ {
#if ( configUSE_TICK_HOOK == 1 )
vApplicationTickHook(); vApplicationTickHook();
#endif /* configUSE_TICK_HOOK */
esp_vApplicationTickHook();
} }
else else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
#endif /* configUSE_TICK_HOOK */
taskEXIT_CRITICAL_ISR(&xTaskQueueMutex); taskEXIT_CRITICAL_ISR(&xTaskQueueMutex);
} }
else else
@ -2533,6 +2534,7 @@ BaseType_t xSwitchRequired = pdFALSE;
vApplicationTickHook(); vApplicationTickHook();
} }
#endif #endif
esp_vApplicationTickHook();
} }
#if ( configUSE_PREEMPTION == 1 ) #if ( configUSE_PREEMPTION == 1 )
@ -3270,6 +3272,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
vApplicationIdleHook(); vApplicationIdleHook();
} }
#endif /* configUSE_IDLE_HOOK */ #endif /* configUSE_IDLE_HOOK */
{
/* Call the esp-idf hook system */
extern void esp_vApplicationIdleHook( void );
esp_vApplicationIdleHook();
}
/* This conditional compilation should use inequality to 0, not equality /* This conditional compilation should use inequality to 0, not equality
to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when

View file

@ -1,13 +1,7 @@
# #
# Component Makefile # Component Makefile
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
# this will take the sources in this directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := include port/include COMPONENT_ADD_INCLUDEDIRS := include port/include
COMPONENT_SRCDIRS := library port COMPONENT_SRCDIRS := library port
include $(IDF_PATH)/make/component_common.mk

View file

@ -1,3 +1,5 @@
COMPONENT_ADD_INCLUDEDIRS := include #
# Component Makefile
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
include $(IDF_PATH)/make/component_common.mk

View file

@ -19,6 +19,10 @@
#include <stdarg.h> #include <stdarg.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#ifdef BOOTLOADER_BUILD
#include <rom/ets_sys.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View file

@ -8,4 +8,3 @@ COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/free
CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
include $(IDF_PATH)/make/component_common.mk

View file

@ -6,4 +6,3 @@ COMPONENT_ADD_INCLUDEDIRS := port/include include
COMPONENT_SRCDIRS := library port COMPONENT_SRCDIRS := library port
include $(IDF_PATH)/make/component_common.mk

View file

@ -0,0 +1,6 @@
# only compile the micro-ecc/uECC.c source file
# (SRCDIRS is needed so build system can find the source file)
COMPONENT_SRCDIRS := micro-ecc
COMPONENT_OBJS := micro-ecc/uECC.o
COMPONENT_ADD_INCLUDEDIRS := micro-ecc

@ -0,0 +1 @@
Subproject commit 14222e062d77f45321676e813d9525f32a88e8fa

View file

@ -1,5 +1,4 @@
COMPONENT_ADD_LDFLAGS := $(abspath lib/libc.a) $(abspath lib/libm.a) -lnewlib COMPONENT_ADD_LDFLAGS := $(COMPONENT_PATH)/lib/libc.a $(COMPONENT_PATH)/lib/libm.a -lnewlib
COMPONENT_ADD_INCLUDEDIRS := include platform_include COMPONENT_ADD_INCLUDEDIRS := include platform_include
include $(IDF_PATH)/make/component_common.mk

View file

@ -5,5 +5,3 @@
COMPONENT_ADD_INCLUDEDIRS := port/include include COMPONENT_ADD_INCLUDEDIRS := port/include include
COMPONENT_SRCDIRS := library port COMPONENT_SRCDIRS := library port
include $(IDF_PATH)/make/component_common.mk

View file

@ -6,4 +6,3 @@ COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_SRCDIRS := src COMPONENT_SRCDIRS := src
include $(IDF_PATH)/make/component_common.mk

View file

@ -7,4 +7,3 @@ COMPONENT_PRIV_INCLUDEDIRS := include/internal include/platform include/openssl
COMPONENT_SRCDIRS := library platform COMPONENT_SRCDIRS := library platform
include $(IDF_PATH)/make/component_common.mk

View file

@ -11,6 +11,8 @@
# NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir # NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir
GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q
PARTITION_TABLE_OFFSET := 0x8000
# Path to partition CSV file is relative to project path for custom # Path to partition CSV file is relative to project path for custom
# partition CSV files, but relative to component dir otherwise.$ # partition CSV files, but relative to component dir otherwise.$
PARTITION_TABLE_ROOT := $(call dequote,$(if $(CONFIG_PARTITION_TABLE_CUSTOM),$(PROJECT_PATH),$(COMPONENT_PATH))) PARTITION_TABLE_ROOT := $(call dequote,$(if $(CONFIG_PARTITION_TABLE_CUSTOM),$(PROJECT_PATH),$(COMPONENT_PATH)))
@ -18,28 +20,38 @@ PARTITION_TABLE_CSV_PATH := $(call dequote,$(abspath $(PARTITION_TABLE_ROOT)/$(s
PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(notdir $(PARTITION_TABLE_CSV_PATH:.csv=.bin)) PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(notdir $(PARTITION_TABLE_CSV_PATH:.csv=.bin))
$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_CSV_PATH) ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN:.bin=-unsigned.bin)
# add an extra signing step for secure partition table
$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_BIN_UNSIGNED)
$(Q) $(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
else
# secure bootloader disabled, both files are the same
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN)
endif
$(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE)
@echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..." @echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..."
$(Q) $(GEN_ESP32PART) $< $@ $(GEN_ESP32PART) $< $@
all_binaries: $(PARTITION_TABLE_BIN) all_binaries: $(PARTITION_TABLE_BIN)
PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash 0x4000 $(PARTITION_TABLE_BIN) PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN)
ESPTOOL_ALL_FLASH_ARGS += 0x4000 $(PARTITION_TABLE_BIN) ESPTOOL_ALL_FLASH_ARGS += $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN)
partition_table: $(PARTITION_TABLE_BIN) partition_table: $(PARTITION_TABLE_BIN)
@echo "Partition table binary generated. Contents:" @echo "Partition table binary generated. Contents:"
@echo $(SEPARATOR) @echo $(SEPARATOR)
$(Q) $(GEN_ESP32PART) $< $(GEN_ESP32PART) $<
@echo $(SEPARATOR) @echo $(SEPARATOR)
@echo "Partition flashing command:" @echo "Partition flashing command:"
@echo "$(PARTITION_TABLE_FLASH_CMD)" @echo "$(PARTITION_TABLE_FLASH_CMD)"
partition_table-flash: $(PARTITION_TABLE_BIN) partition_table-flash: $(PARTITION_TABLE_BIN)
@echo "Flashing partition table..." @echo "Flashing partition table..."
$(Q) $(PARTITION_TABLE_FLASH_CMD) $(PARTITION_TABLE_FLASH_CMD)
partition_table-clean: partition_table-clean:
$(Q) rm -f $(PARTITION_TABLE_BIN) rm -f $(PARTITION_TABLE_BIN)
clean: partition_table-clean clean: partition_table-clean

View file

@ -9,6 +9,8 @@ import struct
import argparse import argparse
import sys import sys
MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature
__version__ = '1.0' __version__ = '1.0'
quiet = False quiet = False
@ -84,15 +86,22 @@ class PartitionTable(list):
@classmethod @classmethod
def from_binary(cls, b): def from_binary(cls, b):
if len(b) % 32 != 0:
raise InputError("Partition table length must be a multiple of 32 bytes. Got %d bytes." % len(b))
result = cls() result = cls()
for o in range(0,len(b),32): for o in range(0,len(b),32):
result.append(PartitionDefinition.from_binary(b[o:o+32])) data = b[o:o+32]
if len(data) != 32:
raise InputError("Ran out of partition table data before reaching end marker")
if data == '\xFF'*32:
break # end of partition table
result.append(PartitionDefinition.from_binary(data))
return result return result
def to_binary(self): def to_binary(self):
return "".join(e.to_binary() for e in self) result = "".join(e.to_binary() for e in self)
if len(result )>= MAX_PARTITION_LENGTH:
raise InputError("Binary partition table length (%d) longer than max" % len(result))
result += "\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
return result
def to_csv(self, simple_formatting=False): def to_csv(self, simple_formatting=False):
rows = [ "# Espressif ESP32 Partition Table", rows = [ "# Espressif ESP32 Partition Table",

View file

@ -37,6 +37,10 @@ LONGER_BINARY_TABLE += "\xAA\x50\x10\x00" + \
"second" + ("\0"*10) + \ "second" + ("\0"*10) + \
"\x00\x00\x00\x00" "\x00\x00\x00\x00"
def _strip_trailing_ffs(binary_table):
while binary_table.endswith("\xFF"):
binary_table = binary_table[0:len(binary_table)-1]
return binary_table
class CSVParserTests(unittest.TestCase): class CSVParserTests(unittest.TestCase):
@ -156,7 +160,7 @@ class BinaryOutputTests(unittest.TestCase):
first, 0x30, 0xEE, 0x100400, 0x300000 first, 0x30, 0xEE, 0x100400, 0x300000
""" """
t = PartitionTable.from_csv(csv) t = PartitionTable.from_csv(csv)
tb = t.to_binary() tb = _strip_trailing_ffs(t.to_binary())
self.assertEqual(len(tb), 32) self.assertEqual(len(tb), 32)
self.assertEqual('\xAA\x50', tb[0:2]) # magic self.assertEqual('\xAA\x50', tb[0:2]) # magic
self.assertEqual('\x30\xee', tb[2:4]) # type, subtype self.assertEqual('\x30\xee', tb[2:4]) # type, subtype
@ -170,7 +174,7 @@ first, 0x30, 0xEE, 0x100400, 0x300000
second,0x31, 0xEF, , 0x100000 second,0x31, 0xEF, , 0x100000
""" """
t = PartitionTable.from_csv(csv) t = PartitionTable.from_csv(csv)
tb = t.to_binary() tb = _strip_trailing_ffs(t.to_binary())
self.assertEqual(len(tb), 64) self.assertEqual(len(tb), 64)
self.assertEqual('\xAA\x50', tb[0:2]) self.assertEqual('\xAA\x50', tb[0:2])
self.assertEqual('\xAA\x50', tb[32:34]) self.assertEqual('\xAA\x50', tb[32:34])
@ -215,7 +219,7 @@ class BinaryParserTests(unittest.TestCase):
self.assertEqual(t[2].type, 0x10) self.assertEqual(t[2].type, 0x10)
self.assertEqual(t[2].name, "second") self.assertEqual(t[2].name, "second")
round_trip = t.to_binary() round_trip = _strip_trailing_ffs(t.to_binary())
self.assertEqual(round_trip, LONGER_BINARY_TABLE) self.assertEqual(round_trip, LONGER_BINARY_TABLE)
def test_bad_magic(self): def test_bad_magic(self):
@ -267,7 +271,7 @@ class CSVOutputTests(unittest.TestCase):
self.assertEqual(row[0], "factory") self.assertEqual(row[0], "factory")
self.assertEqual(row[1], "app") self.assertEqual(row[1], "app")
self.assertEqual(row[2], "2") self.assertEqual(row[2], "2")
self.assertEqual(row[3], "64K") self.assertEqual(row[3], "0x10000")
self.assertEqual(row[4], "1M") self.assertEqual(row[4], "1M")
# round trip back to a PartitionTable and check is identical # round trip back to a PartitionTable and check is identical
@ -291,7 +295,7 @@ class CommandLineTests(unittest.TestCase):
# reopen the CSV and check the generated binary is identical # reopen the CSV and check the generated binary is identical
with open(csvpath, 'r') as f: with open(csvpath, 'r') as f:
from_csv = PartitionTable.from_csv(f.read()) from_csv = PartitionTable.from_csv(f.read())
self.assertEqual(from_csv.to_binary(), LONGER_BINARY_TABLE) self.assertEqual(_strip_trailing_ffs(from_csv.to_binary()), LONGER_BINARY_TABLE)
# run gen_esp32part.py to conver the CSV to binary again # run gen_esp32part.py to conver the CSV to binary again
subprocess.check_call([sys.executable, "../gen_esp32part.py", subprocess.check_call([sys.executable, "../gen_esp32part.py",
@ -299,6 +303,7 @@ class CommandLineTests(unittest.TestCase):
# assert that file reads back as identical # assert that file reads back as identical
with open(binpath, 'rb') as f: with open(binpath, 'rb') as f:
binary_readback = f.read() binary_readback = f.read()
binary_readback = _strip_trailing_ffs(binary_readback)
self.assertEqual(binary_readback, LONGER_BINARY_TABLE) self.assertEqual(binary_readback, LONGER_BINARY_TABLE)
finally: finally:

View file

@ -5,4 +5,3 @@ ifdef IS_BOOTLOADER_BUILD
COMPONENT_OBJS := spi_flash_rom_patch.o COMPONENT_OBJS := spi_flash_rom_patch.o
endif endif
include $(IDF_PATH)/make/component_common.mk

View file

@ -1,5 +1,5 @@
# #
# Component Makefile # Component Makefile
# #
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
include $(IDF_PATH)/make/component_common.mk

View file

@ -372,6 +372,19 @@ wifi_interface_t tcpip_adapter_get_wifi_if(void *dev);
*/ */
esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapter_sta_list_t *tcpip_sta_list); esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapter_sta_list_t *tcpip_sta_list);
#define TCPIP_HOSTNAME_MAX_SIZE 31
/**
* @brief Set the hostname to the interface
*
* @param[in] tcpip_if: the interface which we will set the hostname
* @param[in] hostname: the host name for set the interfce
*
* @return ESP_OK:success
* ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY:interface status error
* ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS:parameter error
*/
esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *hostname);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -607,4 +607,32 @@ esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapt
return ESP_OK; return ESP_OK;
} }
esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *hostname)
{
struct netif *p_netif;
static char hostinfo[TCPIP_HOSTNAME_MAX_SIZE + 1];
if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || hostname == NULL) {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
if (strlen(hostname) >= TCPIP_HOSTNAME_MAX_SIZE) {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
p_netif = esp_netif[tcpip_if];
if (p_netif != NULL) {
if (netif_is_up(p_netif)) {
return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY;
} else {
memset(hostinfo, 0, sizeof(hostinfo));
memcpy(hostinfo, hostname, strlen(hostname));
p_netif->hostname = hostinfo;
return ESP_OK;
}
} else {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
}
#endif #endif

View file

@ -1 +1,5 @@
include $(IDF_PATH)/make/component_common.mk #
# Component Makefile
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -2,5 +2,3 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include
COMPONENT_SRCDIRS := src/crypto COMPONENT_SRCDIRS := src/crypto
CFLAGS += -DEMBEDDED_SUPP -D__ets__ -Wno-strict-aliasing CFLAGS += -DEMBEDDED_SUPP -D__ets__ -Wno-strict-aliasing
include $(IDF_PATH)/make/component_common.mk

View file

@ -1,5 +1,4 @@
# #
# Component Makefile # Component Makefile
# #
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
include $(IDF_PATH)/make/component_common.mk

View file

@ -18,6 +18,11 @@ API Reference
.. _Instructions: template.html .. _Instructions: template.html
Header Files
^^^^^^^^^^^^
* `bt/include/bt.h <https://github.com/espressif/esp-idf/blob/master/components/bt/include/bt.h>`_
Type Definitions Type Definitions
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^

View file

@ -18,6 +18,11 @@ API Reference
.. _Instructions: template.html .. _Instructions: template.html
Header Files
^^^^^^^^^^^^
* `esp32/include/esp_wifi.h <https://github.com/espressif/esp-idf/blob/master/components/esp32/include/esp_wifi.h>`_
Macros Macros
------ ------
@ -28,7 +33,6 @@ Type Definitions
---------------- ----------------
.. doxygentypedef:: wifi_promiscuous_cb_t .. doxygentypedef:: wifi_promiscuous_cb_t
.. doxygentypedef:: wifi_rxcb_t
.. doxygentypedef:: esp_vendor_ie_cb_t .. doxygentypedef:: esp_vendor_ie_cb_t
Functions Functions
@ -68,7 +72,6 @@ Functions
.. doxygenfunction:: esp_wifi_get_config .. doxygenfunction:: esp_wifi_get_config
.. doxygenfunction:: esp_wifi_ap_get_sta_list .. doxygenfunction:: esp_wifi_ap_get_sta_list
.. doxygenfunction:: esp_wifi_set_storage .. doxygenfunction:: esp_wifi_set_storage
.. doxygenfunction:: esp_wifi_reg_rxcb
.. doxygenfunction:: esp_wifi_set_auto_connect .. doxygenfunction:: esp_wifi_set_auto_connect
.. doxygenfunction:: esp_wifi_get_auto_connect .. doxygenfunction:: esp_wifi_get_auto_connect
.. doxygenfunction:: esp_wifi_set_vendor_ie .. doxygenfunction:: esp_wifi_set_vendor_ie

View file

@ -18,8 +18,13 @@ API Reference
.. _Instructions: template.html .. _Instructions: template.html
Header Files
^^^^^^^^^^^^
* `driver/include/driver/driver/gpio.h <https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/gpio.h>`_
Macros Macros
------ ^^^^^^
.. doxygendefine:: GPIO_SEL_0 .. doxygendefine:: GPIO_SEL_0
.. doxygendefine:: GPIO_SEL_1 .. doxygendefine:: GPIO_SEL_1

View file

@ -18,6 +18,11 @@ API Reference
.. _Instructions: template.html .. _Instructions: template.html
Header Files
^^^^^^^^^^^^
* `driver/include/driver/ledc.h <https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/ledc.h>`_
Data Structures Data Structures
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^

View file

@ -1,8 +1,22 @@
.. include:: ../../components/log/README.rst .. include:: ../../components/log/README.rst
Application Example
-------------------
`Instructions`_
API Reference API Reference
------------- -------------
`Instructions`_
.. _Instructions: template.html
Header Files
^^^^^^^^^^^^
* `log/include/esp_log.h <https://github.com/espressif/esp-idf/blob/master/components/log/include/esp_log.h>`_
Macros Macros
^^^^^^ ^^^^^^

View file

@ -1,68 +0,0 @@
.. include:: ../../components/nvs_flash/README.rst
API Reference
-------------
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: nvs_open_mode
Functions
^^^^^^^^^
.. doxygenfunction:: nvs_flash_init
.. doxygenfunction:: nvs_flash_init_custom
.. doxygenfunction:: nvs_open
*Note: the following nvs_set_X function are "the same" except the data type accepted*
.. doxygenfunction:: nvs_set_i8
.. doxygenfunction:: nvs_set_u8
.. doxygenfunction:: nvs_set_i16
.. doxygenfunction:: nvs_set_u16
.. doxygenfunction:: nvs_set_i32
.. doxygenfunction:: nvs_set_u32
.. doxygenfunction:: nvs_set_i64
.. doxygenfunction:: nvs_set_u64
.. doxygenfunction:: nvs_set_str
.. doxygenfunction:: nvs_set_blob
*Note: the following nvs_get_X functions are "the same" except the data type returned*
.. doxygenfunction:: nvs_get_i8
.. doxygenfunction:: nvs_get_u8
.. doxygenfunction:: nvs_get_i16
.. doxygenfunction:: nvs_get_u16
.. doxygenfunction:: nvs_get_i32
.. doxygenfunction:: nvs_get_u32
.. doxygenfunction:: nvs_get_i64
.. doxygenfunction:: nvs_get_u64
.. doxygenfunction:: nvs_get_str
.. doxygenfunction:: nvs_get_blob
.. doxygenfunction:: nvs_erase_key
.. doxygenfunction:: nvs_erase_all
.. doxygenfunction:: nvs_commit
.. doxygenfunction:: nvs_close
Error codes
^^^^^^^^^^^
.. doxygendefine:: ESP_ERR_NVS_BASE
.. doxygendefine:: ESP_ERR_NVS_NOT_INITIALIZED
.. doxygendefine:: ESP_ERR_NVS_NOT_FOUND
.. doxygendefine:: ESP_ERR_NVS_TYPE_MISMATCH
.. doxygendefine:: ESP_ERR_NVS_READ_ONLY
.. doxygendefine:: ESP_ERR_NVS_NOT_ENOUGH_SPACE
.. doxygendefine:: ESP_ERR_NVS_INVALID_NAME
.. doxygendefine:: ESP_ERR_NVS_INVALID_HANDLE
.. doxygendefine:: ESP_ERR_NVS_REMOVE_FAILED
.. doxygendefine:: ESP_ERR_NVS_KEY_TOO_LONG
.. doxygendefine:: ESP_ERR_NVS_PAGE_FULL
.. doxygendefine:: ESP_ERR_NVS_INVALID_STATE
.. doxygendefine:: ESP_ERR_NVS_INVALID_LENGTH

View file

@ -8,6 +8,12 @@ Application Example
API Reference API Reference
------------- -------------
Header Files
^^^^^^^^^^^^
* `nvs_flash/include/nvs_flash.h <https://github.com/espressif/esp-idf/blob/master/components/nvs_flash/include/nvs_flash.h>`_
* `nvs_flash/include/nvs.h <https://github.com/espressif/esp-idf/blob/master/components/nvs_flash/include/nvs.h>`_
Macros Macros
^^^^^^ ^^^^^^

View file

@ -51,10 +51,11 @@ API Reference
*INSTRUCTIONS* *INSTRUCTIONS*
1. Provide list of API members divided into sections. 1. Specify the names of header files used to generate this reference. Each name should be linked to the source on `espressif/esp-idf <https://github.com/espressif/esp-idf>`_ repository.
2. Use corresponding ``.. doxygen..`` directives, so member documentation is auto updated. 2. Provide list of API members divided into sections.
3. Use corresponding ``.. doxygen..`` directives, so member documentation is auto updated.
* Data Structures -``.. doxygenstruct::`` * Data Structures -``.. doxygenstruct::`` together with ``:members:``
* Macros - ``.. doxygendefine::`` * Macros - ``.. doxygendefine::``
* Type Definitions - ``.. doxygentypedef::`` * Type Definitions - ``.. doxygentypedef::``
* Enumerations - ``.. doxygenenum::`` * Enumerations - ``.. doxygenenum::``
@ -62,30 +63,48 @@ API Reference
See `Breathe documentation <https://breathe.readthedocs.io/en/latest/directives.html>`_ for additional information. See `Breathe documentation <https://breathe.readthedocs.io/en/latest/directives.html>`_ for additional information.
3. Once done remove superfluous headers. 4. Once done remove superfluous headers.
4. When changes are committed and documentation is build, check how this section rendered. :doc:`Correct annotations <../documenting-code>` in respective header files, if required. 5. When changes are committed and documentation is build, check how this section rendered. :doc:`Correct annotations <../documenting-code>` in respective header files, if required.
Header Files
^^^^^^^^^^^^
* `path/header-file.h`
Data Structures Data Structures
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
``.. doxygenstruct:: name_of_structure`` ::
.. doxygenstruct:: name_of_structure
:members:
Macros Macros
^^^^^^ ^^^^^^
``.. doxygendefine:: name_of_macro`` ::
.. doxygendefine:: name_of_macro
Type Definitions Type Definitions
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
``.. doxygentypedef:: name_of_type`` ::
.. doxygentypedef:: name_of_type
Enumerations Enumerations
^^^^^^^^^^^^ ^^^^^^^^^^^^
``.. doxygenenum:: name_of_enumeration`` ::
.. doxygenenum:: name_of_enumeration
Functions Functions
^^^^^^^^^ ^^^^^^^^^
``.. doxygenfunction:: name_of_function`` ::
.. doxygenfunction:: name_of_function

98
docs/api/uart.rst Normal file
View file

@ -0,0 +1,98 @@
UART
====
Overview
--------
`Instructions`_
Application Example
-------------------
`Instructions`_
API Reference
-------------
`Instructions`_
.. _Instructions: template.html
Header Files
^^^^^^^^^^^^
* `driver/include/driver/uart.h <https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/uart.h>`_
Data Structures
^^^^^^^^^^^^^^^
.. doxygenstruct:: uart_config_t
:members:
.. doxygenstruct:: uart_intr_config_t
:members:
.. doxygenstruct:: uart_event_t
:members:
Macros
^^^^^^
.. doxygendefine:: UART_FIFO_LEN
.. doxygendefine:: UART_INTR_MASK
.. doxygendefine:: UART_LINE_INV_MASK
.. doxygendefine:: UART_BITRATE_MAX
.. doxygendefine:: UART_PIN_NO_CHANGE
.. doxygendefine:: UART_INVERSE_DISABLE
.. doxygendefine:: UART_INVERSE_RXD
.. doxygendefine:: UART_INVERSE_CTS
.. doxygendefine:: UART_INVERSE_TXD
.. doxygendefine:: UART_INVERSE_RTS
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: uart_word_length_t
.. doxygenenum:: uart_stop_bits_t
.. doxygenenum:: uart_port_t
.. doxygenenum:: uart_parity_t
.. doxygenenum:: uart_hw_flowcontrol_t
.. doxygenenum:: uart_event_type_t
Functions
^^^^^^^^^
.. doxygenfunction:: uart_set_word_length
.. doxygenfunction:: uart_get_word_length
.. doxygenfunction:: uart_set_stop_bits
.. doxygenfunction:: uart_get_stop_bits
.. doxygenfunction:: uart_set_parity
.. doxygenfunction:: uart_get_parity
.. doxygenfunction:: uart_set_baudrate
.. doxygenfunction:: uart_get_baudrate
.. doxygenfunction:: uart_set_line_inverse
.. doxygenfunction:: uart_set_hw_flow_ctrl
.. doxygenfunction:: uart_get_hw_flow_ctrl
.. doxygenfunction:: uart_clear_intr_status
.. doxygenfunction:: uart_enable_intr_mask
.. doxygenfunction:: uart_disable_intr_mask
.. doxygenfunction:: uart_enable_rx_intr
.. doxygenfunction:: uart_disable_rx_intr
.. doxygenfunction:: uart_disable_tx_intr
.. doxygenfunction:: uart_enable_tx_intr
.. doxygenfunction:: uart_isr_register
.. doxygenfunction:: uart_set_pin
.. doxygenfunction:: uart_set_rts
.. doxygenfunction:: uart_set_dtr
.. doxygenfunction:: uart_param_config
.. doxygenfunction:: uart_intr_config
.. doxygenfunction:: uart_driver_install
.. doxygenfunction:: uart_driver_delete
.. doxygenfunction:: uart_wait_tx_done
.. doxygenfunction:: uart_tx_chars
.. doxygenfunction:: uart_write_bytes
.. doxygenfunction:: uart_write_bytes_with_break
.. doxygenfunction:: uart_read_bytes
.. doxygenfunction:: uart_flush

View file

@ -8,6 +8,12 @@ Application Example
API Reference API Reference
------------- -------------
Header Files
^^^^^^^^^^^^
* `vfs/include/esp_vfs.h <https://github.com/espressif/esp-idf/blob/master/components/vfs/include/esp_vfs.h>`_
* `vfs/include/esp_vfs_dev.h <https://github.com/espressif/esp-idf/blob/master/components/vfs/include/esp_vfs_dev.h>`_
Macros Macros
^^^^^^ ^^^^^^

View file

@ -8,262 +8,380 @@ Read this document if you want to know how to organise a new ESP-IDF project.
We recommend using the esp-idf-template_ project as a starting point for your project. We recommend using the esp-idf-template_ project as a starting point for your project.
Using the Build System
======================
The esp-idf README file contains a description of how to use the build system to build your project.
Overview Overview
======== ========
An ESP-IDF project can be seen as an almagation of a number of components. An ESP-IDF project can be seen as an amalgamation of a number of components.
For example, for a webserver that shows the current humidity, we would For example, for a webserver that shows the current humidity, there could be:
have:
- The ESP32 base libraries (libc, rom bindings etc) - The ESP32 base libraries (libc, rom bindings etc)
- The WiFi drivers - The WiFi drivers
- A TCP/IP stack - A TCP/IP stack
- The FreeRTOS operating system - The FreeRTOS operating system
- A webserver - A webserver
- A driver for an humidity sensor - A driver for the humidity sensor
- Main code tying it all together - Main code tying it all together
ESP-IDF makes these components explicit and configurable. To do that, when a project ESP-IDF makes these components explicit and configurable. To do that,
is compiled, the build environment will look up all the components in the when a project is compiled, the build environment will look up all the
ESP-IDF directories, the project directories and optionally custom other component components in the ESP-IDF directories, the project directories and
directories. It then allows the user to configure compile-time options using (optionally) in additional custom component directories. It then
a friendly text-based menu system to customize the ESP-IDF as well as other components allows the user to configure the ESP-IDF project using a a text-based
to the requirements of the project. After the components are customized, the menu system to customize each component. After the components in the
build process will compile everything into an output file, which can then be uploaded project are configured, the build process will compile the project.
into a board in a way that can also be defined by components.
A project in this sense is defined as a directory under which all the files required Concepts
to build it live, excluding the ESP-IDF files and the toolchain. A simple project --------
tree might look like this::
- myProject/ - build/ - A "project" is a directory that contains all the files and configuration to build a single "app" (executable), as well as additional supporting output such as a partition table, data/filesystem partitions, and a bootloader.
- "Project configuration" is held in a single file called sdkconfig in the root directory of the project. This configuration file is modified via ``make menuconfig`` to customise the configuration of the project. A single project contains exactly one project configuration.
- An "app" is an executable which is built by esp-idf. A single project will usually build two apps - a "project app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader program which launches the project app).
- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by esp-idf itself, others may be sourced from other places.
Some things are not part of the project:
- "ESP-IDF" is not part of the project. Instead it is standalone, and linked to the project via the ``IDF_PATH`` environment variable which holds the path of the ``esp-idf`` directory. This allows the IDF framework to be decoupled from your project.
- The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH, or the path to the toolchain can be set as part of the compiler prefix in the project configuration.
Example Project
---------------
An example project directory tree might look like this::
- myProject/
- Makefile
- sdkconfig
- components/ - component1/ - component.mk - components/ - component1/ - component.mk
- Kconfig - Kconfig
- src1.c - src1.c
- component2/ - component.mk - component2/ - component.mk
- Kconfig - Kconfig
- src1.c - src1.c
- include/
- component2.h
- main/ - src1.c - main/ - src1.c
- src2.c - src2.c
- Makefile - component.mk
- build/
As we can see, a project consists of a components/ subdirectory containing its This example "myProject" contains the following elements:
components as well as one or more directories containing the project-specific
sources; by default a single directory called 'main' is assumed. The project
directory will also have a Makefile where the projects name as well as optionally
other options are defined. After compilation, the project directory will contain
a 'build'-directory containing all of the objects, libraries and other generated
files as well as the final binary.
Components also have a custom makefile - ``component.mk``. This contains various definititions - A top-level project Makefile. This Makefile set the ``PROJECT_NAME`` variable and (optionally) defines
influencing the build process of the component as well as the project it's used other project-wide make variables. It includes the core ``$(IDF_PATH)/make/project.mk`` makefile which
in. Components may also include a Kconfig file defining the compile-time options that are implements the rest of the ESP-IDF build system.
settable by means of the menu system.
Project Makefile variables that can be set by the programmer:: - "sdkconfig" project configuration file. This file is created/updated when "make menuconfig" runs, and holds configuration for all of the components in the project (including esp-idf itself). The "sdkconfig" file may or may not be added to the source control system of the project.
PROJECT_NAME: Mandatory. Name for the project - Optional "components" directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren't part of ESP-IDF.
BUILD_DIR_BASE: Set the directory where all objects/libraries/binaries end up in.
Defaults to $(PROJECT_PATH)/build
COMPONENT_DIRS: Search path for components. Defaults to the component/ directories
in the ESP-IDF path and the project path.
COMPONENTS: A list of component names. Defaults to all the component found in the
COMPONENT_DIRS directory
EXTRA_COMPONENT_DIRS: Defaults to unset. Use this to add directories to the default
COMPONENT_DIRS.
SRCDIRS: Directories under the project dir containing project-specific sources.
Defaults to 'main'. These are treated as 'lite' components: they do not have
include directories that are passed to the compilation pass of all components and
they do not have a Kconfig option.
Component-specific component.mk variables that can be set by the programmer:: - "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the Makefile variable ``SRCDIRS`` defaults to this but can be set to look for pseudo-components in other directories.
COMPONENT_ADD_INCLUDEDIRS: Relative path to include directories to be added to - "build" directory is where build output is created. After the make process is run, this directory will contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code.
the entire project. If an include directory is only needed to compile this
specific component, don't add it here. Component directories contain a component makefile - ``component.mk``. This may contain variable definitions
COMPONENT_PRIV_INCLUDEDIRS: Relative path to include directories that are only used to control the build process of the component, and its integration into the overall project. See `Component Makefiles` for more details.
when compiling this specific component.
COMPONENT_DEPENDS: Names of any components that need to be compiled before this component. Each component may also include a ``Kconfig`` file defining the `component configuration` options that can be set via the project configuration. Some components may also include ``Kconfig.projbuild`` and ``Makefile.projbuild`` files, which are special files for `overriding parts of the project`.
COMPONENT_ADD_LDFLAGS: LD flags to add for the entire project. Defaults to -l$(COMPONENT_NAME).
Add libraries etc in the current directory as $(abspath libwhatever.a) Project Makefiles
COMPONENT_EXTRA_INCLUDES: Any extra include paths used when compiling the component's -----------------
source files. These will be prefixed with '-I' and passed to the compiler.
Similar to COMPONENT_PRIV_INCLUDEDIRS, but these paths are passed as-is instead of Each project has a single Makefile that contains build settings for the entire project. By default, the project Makefile can be quite minimal.
Minimal Example Makefile
^^^^^^^^^^^^^^^^^^^^^^^^
::
PROJECT_NAME := myProject
include $(IDF_PATH)/make/project.mk
Mandatory Project Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``PROJECT_NAME``: Name of the project. Binary output files will use this name - ie myProject.bin, myProject.elf.
Optional Project Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^
These variables all have default values that can be overridden for custom behaviour. Look in ``make/project.mk`` for all of the implementation details.
- ``PROJECT_PATH``: Top-level project directory. Defaults to the directory containing the Makefile. Many other project variables are based on this variable. The project path cannot contain spaces.
- ``BUILD_DIR_BASE``: The build directory for all objects/libraries/binaries. Defaults to ``$(PROJECT_PATH)/build``.
- ``COMPONENT_DIRS``: Directories to search for components. Defaults to `$(IDF_PATH)/components`, `$(PROJECT_PATH)/components` and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in the esp-idf & project ``components`` directories.
- ``EXTRA_COMPONENT_DIRS``: Optional list of additional directories to search for components. Components themselves are in sub-directories of these directories, this is a top-level directory containing the component directories.
- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the COMPONENT_DIRS directories.
- ``SRCDIRS``: Directories under the main project directory which contain project-specific "pseudo-components". Defaults to 'main'. The difference between specifying a directory here and specifying it under ``EXTRA_COMPONENT_DIRS`` is that a directory in ``SRCDIRS`` is a component itself (contains a file "component.mk"), whereas a directory in ``EXTRA_COMPONENT_DIRS`` contains component directories which contain a file "component.mk". See the `Example Project` for a concrete case of this.
Component Makefiles
-------------------
Each project contains one or more components, which can either be part of esp-idf or added from other component directories.
A component is any sub-directory that contains a `component.mk` file.[#f1]_.
Minimal Component Makefile
^^^^^^^^^^^^^^^^^^^^^^^^^^
The minimal ``component.mk`` file is an empty file(!). If the file is empty, the default component behaviour is set:
- All source files in the same directory as the makefile (*.c, *.cpp, *.S) will be compiled into the component library
- A sub-directory "include" will be added to the global include search path for all other components.
- The component library will be linked into the project app.
See `example component makefiles` for more complete component makefile examples.
Note that there is a different between an empty ``component.mk`` file (which invokes default component build behaviour) and no ``component.mk`` file (which means no default component build behaviour will occur.) It is possible for a component to have no `component.mk` file, if it only contains other files which influence the project configuration or build process.
.. component variables:
Preset Component Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^
The following component-specific variables are available for use inside ``component.mk``, but should not be modified:
- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces.
- ``COMPONENT_NAME``: Name of the component. Defaults to the name of the component directory.
- ``COMPONENT_BUILD_DIR``: The component build directory. Evaluates to the absolute path of a directory inside `$(BUILD_DIR_BASE)` where this component's source files are to be built. This is also the Current Working Directory any time the component is being built, so relative paths in make targets, etc. will be relative to this directory.
- ``COMPONENT_LIBRARY``: Name of the static library file (relative to the component build directory) that will be built for this component. Defaults to ``$(COMPONENT_NAME).a``.
The following variables are set at the project level, but exported for use in the component build:
- ``PROJECT_NAME``: Name of the project, as set in project Makefile
- ``PROJECT_PATH``: Absolute path of the project directory containing the project Makefile.
- ``COMPONENTS``: Name of all components that are included in this build.
- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``.
- ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain.
- ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain.
If you modify any of these variables inside ``component.mk`` then this will not prevent other components from building but it may make your component hard to build and/or debug.
Optional Project-Wide Component Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following variables can be set inside ``component.mk`` to control build settings across the entire project:
- ``COMPONENT_ADD_INCLUDEDIRS``: Paths, relative to the component
directory, which will be added to the include search path for
all components in the project. Defaults to ``include`` if not overridden. If an include directory is only needed to compile
this specific component, add it to ``COMPONENT_PRIV_INCLUDEDIRS`` instead.
- ``COMPONENT_ADD_LDFLAGS``: Add linker arguments to the LDFLAGS for
the app executable. Defaults to ``-l$(COMPONENT_NAME)``. If
adding pre-compiled libraries to this directory, add them as
absolute paths - ie $(COMPONENT_PATH)/libwhatever.a
- ``COMPONENT_DEPENDS``: Optional list of component names that should
be compiled before this component. This is not necessary for
link-time dependencies, because all component include directories
are available at all times. It is necessary if one component
generates an include file which you then want to include in another
component. Most components do not need to set this variable.
Optional Component-Specific Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following variables can be set inside ``component.mk`` to control the build of that component:
- ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to
the component directory, which will be added to the include search
path for this component's source files only.
- ``COMPONENT_EXTRA_INCLUDES``: Any extra include paths used when
compiling the component's source files. These will be prefixed with
'-I' and passed as-is to the compiler. Similar to the
``COMPONENT_PRIV_INCLUDEDIRS`` variable, except these paths are not
expanded relative to the component directory. expanded relative to the component directory.
COMPONENT_SRCDIRS: Relative directories to look in for sources. Defaults to '.', the current - ``COMPONENT_SRCDIRS``: Directory paths, must be relative to the
directory (the root of the component) only. Use this to specify any subdirectories. Note component directory, which will be searched for source files (*.cpp,
that specifying this overwrites the default action of compiling everything in the *.c, *.S). Defaults to '.', ie the component directory
components root dir; to keep this behaviour please also add '.' as a directory in this itself. Override this to specify a different list of directories
list. which contain source files.
COMPONENT_OBJS: Object files to compile. Defaults to the .o variants of all .c and .S files - ``COMPONENT_OBJS``: Object files to compile. Default value is a .o
that are found in COMPONENT_SRCDIRS. file for each source file that is found in ``COMPONENT_SRCDIRS``.
COMPONENT_EXTRA_CLEAN: Files that are generated using rules in the components Makefile Overriding this list allows you to exclude source files in
that also need to be cleaned ``COMPONENT_SRCDIRS`` that would otherwise be compiled. See
COMPONENT_BUILDRECIPE: Recipe to build the component. Optional. Defaults to building all `Specifying source files`
COMPONENT_OBJS and linking them into lib(componentname).a - ``COMPONENT_EXTRA_CLEAN``: Paths, relative to the component build
COMPONENT_CLEANRECIPE: Recipe to clean the component. Optional. Defaults to removing directory, of any files that are generated using custom make rules
all built objects and libraries. in the component.mk file and which need to be removed as part of
COMPONENT_BUILD_DIR: Equals the cwd of the component build, which is the build dir ``make clean``. See `Source Code Generation` for an example.
of the component (where all the .o etc files should be created). - ``COMPONENT_OWNBUILDTARGET`` & `COMPONENT_OWNCLEANTARGET`: These
targets allow you to fully override the default build behaviour for
the component. See `Fully Overriding The Component Makefile` for
more details.
- ``CFLAGS``: Flags passed to the C compiler. A default set of
``CFLAGS`` is defined based on project settings. Component-specific
additions can be made via ``CFLAGS +=``. It is also possible
(although not recommended) to override this variable completely for
a component.
- ``CPPFLAGS``: Flags passed to the C preprocessor (used for .c, .cpp
and .S files). A default set of ``CPPFLAGS`` is defined based on
project settings. Component-specific additions can be made via
``CPPFLAGS +=``. It is also possible (although not recommended) to
override this variable completely for a component.
- ``CXXFLAGS``: Flags passed to the C++ compiler. A default set of
``CXXFLAGS`` is defined based on project
settings. Component-specific additions can be made via ``CXXFLAGS
+=``. It is also possible (although not recommended) to override
this variable completely for a component.
These variables are already set early on in the Makefile and the values in it will Component Configuration
be usable in component or project Makefiles:: -----------------------
CC, LD, AR, OBJCOPY: Xtensa gcc tools Each component can also have a Kconfig file, alongside ``component.mk``. This contains contains
HOSTCC, HOSTLD etc: Host gcc tools configuration settings to add to the "make menuconfig" for this component.
LDFLAGS, CFLAGS: Set to usable values as defined in ESP-IDF Makefile
PROJECT_NAME: Name of the project, as set in project makefile
PROJECT_PATH: Path to the root of the project folder
COMPONENTS: Name of the components to be included
CONFIG_*: All values set by 'make menuconfig' have corresponding Makefile variables.
Inside your component's component.mk makefile, you can override or add to these variables These settings are found under the "Component Settings" menu when menuconfig is run.
as necessary. The changes are isolated from other components (see Makefile.projbuild below
if you want to share these changes with all other components.)
For components, there also are these defines:: To create a component KConfig file, it is easiest to start with one of the KConfig files distributed with esp-idf.
COMPONENT_PATH: Absolute path to the root of the source tree of the component we're For an example, see `Adding conditional configuration`.
compiling
COMPONENT_LIBRARY: The full path to the static library the components compilation pass
is supposed to generate
Make Process Build Process Internals
------------ -----------------------
The Make process is always invoked from the project directory by the Top Level: Project Makefile
user; invoking it anywhere else gives an error. This is what happens if ^^^^^^^^^^^^^^^^^^^^^^^^^^^
we build a binary:
The Makefile first determines how it was included. It figures out - "make" is always run from the project directory and the project makefile, typically named Makefile.
various paths as well as the components available to it. It will also - The project makefile sets ``PROJECT_NAME`` and optionally customises other `optional project variables`
collect the ldflags and includes that the components specify they need. - The project makefile includes ``$(IDF_PATH)/make/project.mk`` which contains the project-level Make logic.
It does this by running a dummy make on the components with a "get_variable" - ``project.mk`` fills in default project-level make variables and includes make variables from the project configuration. If the generated makefile containing project configuration is out of date, then it is regenerated (via targets in ``project_config.mk``) and then the make process restarts from the top.
target that will output these values. - ``project.mk`` builds a list of components to build, based on the default component directories or a custom list of components set in `optional project variables`.
- Each component can set some `optional project-wide component variables`. These are included via generated makefiles named ``component_project_vars.mk`` - there is one per component. These generated makefiles are included into ``project.mk``. If any are missing or out of date, they are regenerated (via a recursive make call to the component makefile) and then the make process restarts from the top.
- `Makefile.projbuild` files from components are included into the make process, to add extra targets or configuration.
- By default, the project makefile also generates top-level build & clean targets for each component and sets up `app` and `clean` targets to invoke all of these sub-targets.
- In order to compile each component, a recursive make is performed for the component makefile.
The Makefile will then create targets to build the lib*.a libraries of To better understand the project make process, have a read through the ``project.mk`` file itself.
all components and make the elf target depend on this. The main Makefile
invokes Make on the componen.mk of each components inside a sub-mke: this way
the components have full freedom to do whatever is necessary to build
the library without influencing other components. By default, the
component.mk includes the utility makefile $(IDF_PATH)/make/component_common.mk.
This provides default targets and configurations that will work
out-of-the-box for most projects.
KConfig Second Level: Component Makefiles
------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Each component can also have a Kconfig file, alongside the component.mk, that contains - Each call to a component makefile goes via the ``$(IDF_PATH)/make/component_wrapper.mk`` wrapper makefile.
details to add to "menuconfig" for this component. - The ``component_wrapper.mk`` is called with the current directory set to the component build directory, and the ``COMPONENT_MAKEFILE`` variable is set to the absolute path to ``component.mk``.
- ``component_wrapper.mk`` sets default values for all `component variables`, then includes the `component.mk` file which can override or modify these.
- If ``COMPONENT_OWNBUILDTARGET`` and ``COMPONENT_OWNCLEANTARGET`` are not defined, default build and clean targets are created for the component's source files and the prerequisite ``COMPONENT_LIBRARY`` static library file.
- The ``component_project_vars.mk`` file has its own target in ``component_wrapper.mk``, which is evaluated from ``project.mk`` if this file needs to be rebuilt due to changes in the component makefile or the project configuration.
To better understand the component make process, have a read through the ``component_wrapper.mk`` file and some of the ``component.mk`` files included with esp-idf.
Debugging The Make Process
--------------------------
Some tips for debugging the esp-idf build system:
- Appending ``V=1`` to the make arguments (or setting it as an environment variable) will cause make to echo all commands executed, and also each directory as it is entered for a sub-make.
- Running ``make -w`` will cause make to echo each directory as it is entered for a sub-make - same as ``V=1`` but without also echoing all commands.
- Running ``make --trace`` (possibly in addition to one of the above arguments) will print out every target as it is built, and the dependency which caused it to be built.
- Running ``make -p`` prints a (very verbose) summary of every generated target in each makefile.
For more debugging tips and general make information, see the `GNU Make Manual`.
Overriding Parts of the Project
-------------------------------
Makefile.projbuild Makefile.projbuild
------------------ ^^^^^^^^^^^^^^^^^^
For components that have parts that need to be evaluated in the top-level For components that have build requirements that must be evaluated in the top-level
project context, you can create a file called Makefile.projbuild in the project make pass, you can create a file called ``Makefile.projbuild`` in the
component root directory. These files is included into the project's component directory. This makefile is included when ``project.mk`` is evaluated.
top-level Makefile.
For example, if your component needs to add to CFLAGS for the entire For example, if your component needs to add to CFLAGS for the entire
project (not just for its own source files) then you can set project (not just for its own source files) then you can set
``CFLAGS +=`` in Makefile.projbuild. Note that this isn't necessary for ``CFLAGS +=`` in Makefile.projbuild.
adding include directories to the project, you can set
``COMPONENT_ADD_INCLUDEDIRS`` (see above) in the component.mk.
``Makefile.projbuild`` files are used heavily inside esp-idf, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app".
Note that ``Makefile.projbuild`` isn't necessary for the most common component uses - such as adding include directories to the project, or LDFLAGS to the final linking step. These values can be customised via the ``component.mk`` file itself. See `Optional Project-Wide Component Variables` for details.
Take care when setting variables or targets in this file. As the values are included into the top-level project makefile pass, they can influence or break functionality across all components!
KConfig.projbuild KConfig.projbuild
----------------- ^^^^^^^^^^^^^^^^^
There's an equivalent to Makefile.projbuild for KConfig: if you want to include This is an equivalent to `Makefile.projbuild` for `component configuration` KConfig files. If you want to include
options at the top-level, not inside the 'components' submenu then create a Kconfig.projbuild and configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``component.mk`` file.
it will be included in the main menu of menuconfig.
Take good care when (re)defining stuff here: because it's included with all the other Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for `component configuration`.
.projbuild files, it's possible to overwrite variables or re-declare targets defined in
the ESP-IDF makefile/Kconfig and other .projbuild files. It's generally better to just
create a KConfig file, if you can.
Writing Component Makefiles Example Component Makefiles
--------------------------- ---------------------------
A component consists of a directory which doubles as the name for the Because the build environment tries to set reasonable defaults that will work most
component: a component named 'httpd' lives in a directory called 'httpd' of the time, component.mk can be very small or even empty (see `Minimal Component Makefile`). However, overriding `component variables` is usually required for some functionality.
Because components usually live under the project directory (although
they can also reside in an other folder), the path to this may be
something like /home/myuser/projects/myprojects/components/httpd .
Components can have any name (unique to the project) but the name Here are some more advanced examples of ``component.mk`` makefiles:
cannot contain spaces (esp-idf does not support spaces in paths).
One of the things that most components will have is a component.mk makefile,
containing instructions on how to build the component. Because the
build environment tries to set reasonable defaults that will work most
of the time, component.mk can be very small.
Simplest component.mk
=====================
At the minimum, component.mk will just include the ESP-IDF component "common" makefile,
which adds common component functionality::
include $(IDF_PATH)/make/component_common.mk
This will take all the .c and .S files in the component root and compile
them into object files, finally linking them into a library.
Adding source directories Adding source directories
========================= ^^^^^^^^^^^^^^^^^^^^^^^^^
By default, subdirectories are ignored. If your project has sources in subdirectories By default, sub-directories are ignored. If your project has sources in sub-directories
instead of in the root of the component then you can tell that to the build instead of in the root of the component then you can tell that to the build
system by setting COMPONENT_SRCDIRS:: system by setting ``COMPONENT_SRCDIRS``::
COMPONENT_SRCDIRS := src1 src2 COMPONENT_SRCDIRS := src1 src2
include $(IDF_PATH)/make/component_common.mk
This will compile all source files in the src1/ and src2/ subdirectories This will compile all source files in the src1/ and src2/ sub-directories
instead. instead.
Specifying source files Specifying source files
======================= ^^^^^^^^^^^^^^^^^^^^^^^
The standard component.mk logic adds all .S and .c files in the source The standard component.mk logic adds all .S and .c files in the source
directories as sources to be compiled unconditionally. It is possible directories as sources to be compiled unconditionally. It is possible
to circumvent that logic and hardcode the objects to be compiled by to circumvent that logic and hard-code the objects to be compiled by
manually setting the COMPONENT_OBJS variable to the name of the manually setting the ``COMPONENT_OBJS`` variable to the name of the
objects that need to be generated:: objects that need to be generated::
COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o
include $(IDF_PATH)/make/component_common.mk COMPONENT_SRCDIRS := . thing anotherthing
Note that ``COMPONENT_SRCDIRS`` must be set as well.
Adding conditional configuration Adding conditional configuration
================================ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The configuration system can be used to conditionally compile some files The configuration system can be used to conditionally compile some files
dependending on the options selected in ``make menuconfig``: depending on the options selected in ``make menuconfig``:
Kconfig:: ``Kconfig``::
config FOO_ENABLE_BAR config FOO_ENABLE_BAR
bool "Enable the BAR feature." bool "Enable the BAR feature."
help help
This enables the BAR feature of the FOO component. This enables the BAR feature of the FOO component.
Makefile:: ``component.mk``::
COMPONENT_OBJS := foo_a.o foo_b.o $(if $(CONFIG_FOO_ENABLE_BAR),foo_bar.o foo_bar_interface.o) COMPONENT_OBJS := foo_a.o foo_b.o
include $(IDF_PATH)/make/component_common.mk
ifdef CONFIG_FOO_BAR
COMPONENT_OBJS += foo_bar.o foo_bar_interface.o
endif
See the `GNU Make Manual` for conditional syntax that can be used use in makefiles.
Source Code Generation Source Code Generation
====================== ^^^^^^^^^^^^^^^^^^^^^^
Some components will have a situation where a source file isn't supplied Some components will have a situation where a source file isn't
with the component itself but has to be generated from another file. Say supplied with the component itself but has to be generated from
our component has a header file that consists of the converted binary another file. Say our component has a header file that consists of the
data of a BMP file, converted using a hypothetical tool called bmp2h. The converted binary data of a BMP file, converted using a hypothetical
header file is then included in as C source file called graphics_lib.c:: tool called bmp2h. The header file is then included in as C source
file called graphics_lib.c::
COMPONENT_EXTRA_CLEAN := logo.h COMPONENT_EXTRA_CLEAN := logo.h
@ -272,7 +390,6 @@ header file is then included in as C source file called graphics_lib.c::
logo.h: $(COMPONENT_PATH)/logo.bmp logo.h: $(COMPONENT_PATH)/logo.bmp
bmp2h -i $^ -o $@ bmp2h -i $^ -o $@
include $(IDF_PATH)/make/component_common.mk
In this example, graphics_lib.o and logo.h will be generated in the In this example, graphics_lib.o and logo.h will be generated in the
current directory (the build directory) while logo.bmp comes with the current directory (the build directory) while logo.bmp comes with the
@ -281,24 +398,42 @@ generated file, it needs to be cleaned when make clean is called which
why it is added to the COMPONENT_EXTRA_CLEAN variable. why it is added to the COMPONENT_EXTRA_CLEAN variable.
Cosmetic Improvements Cosmetic Improvements
===================== ^^^^^^^^^^^^^^^^^^^^^
The above example will work just fine, but there's one last cosmetic Because logo.h is a generated file, it needs to be cleaned when make
improvement that can be done. The make system tries to make the make clean is called which why it is added to the COMPONENT_EXTRA_CLEAN
process somewhat easier on the eyes by hiding the commands (unless you variable.
run make with the V=1 switch) and this does not do that yet. Here's an
improved version that will output in the same style as the rest of the
make process::
COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h Adding logo.h to the ``graphics_lib.o`` dependencies causes it to be
generated before ``graphics_lib.c`` is compiled.
graphics_lib.o: logo.h If a a source file in another component included ``logo.h``, then this
component's name would have to be added to the other component's
``COMPONENT_DEPENDS`` list to ensure that the components were built
in-order.
logo.h: $(COMPONENT_PATH)/logo.bmp Embedding Binary Data
$(summary) BMP2H $@ ^^^^^^^^^^^^^^^^^^^^^
$(Q) bmp2h -i $^ -o $@
Sometimes you have a file with some binary or text data that you'd like to make available to your component - but you don't want to reformat the file as C source.
You can set a variable COMPONENT_EMBED_FILES in component.mk, giving the names of the files to embed in this way::
COMPONENT_EMBED_FILES := server_root_cert.der
Or if the file is a string, you can use the variable COMPONENT_EMBED_TXTFILES. This will embed the contents of the text file as a null-terminated string::
COMPONENT_EMBED_TXTFILES := server_root_cert.pem
The file's contents will be added to the .rodata section in flash, and are available via symbol names as follows::
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
The names are generated from the full name of the file, as given in COMPONENT_EMBED_FILES. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files.
For an example of using this technique, see examples/04_https_request - the certificate file contents are loaded from the text .pem file at compile time.
include $(IDF_PATH)/make/component_common.mk
Fully Overriding The Component Makefile Fully Overriding The Component Makefile
--------------------------------------- ---------------------------------------
@ -307,12 +442,15 @@ Obviously, there are cases where all these recipes are insufficient for a
certain component, for example when the component is basically a wrapper certain component, for example when the component is basically a wrapper
around another third-party component not originally intended to be around another third-party component not originally intended to be
compiled under this build system. In that case, it's possible to forego compiled under this build system. In that case, it's possible to forego
the build system entirely by setting COMPONENT_OWNBUILDTARGET and the esp-idf build system entirely by setting COMPONENT_OWNBUILDTARGET and
possibly COMPONENT_OWNCLEANTARGET and defining your own build- and clean possibly COMPONENT_OWNCLEANTARGET and defining your own targets named ``build`` and ``clean`` in ``component.mk``
target. The build target can do anything as long as it creates target. The build target can do anything as long as it creates
$(COMPONENT_LIBRARY) for the main file to link into the project binary, $(COMPONENT_LIBRARY) for the project make process to link into the app binary.
and even that is not necessary: if the COMPONENT_ADD_LDFLAGS variable
is set, the component can instruct the linker to do anything else as well. (Actually, even this is not strictly necessary - if the COMPONENT_ADD_LDFLAGS variable
is set then the component can instruct the linker to link other binaries instead.)
.. _esp-idf-template: https://github.com/espressif/esp-idf-template .. _esp-idf-template: https://github.com/espressif/esp-idf-template
.. _GNU Make Manual: https://www.gnu.org/software/make/manual/make.html
.. _[_f1]: Actually, some components in esp-idf are "pure configuration" components that don't have a component.mk file, only a Makefile.projbuild and/or Kconfig.projbuild file. However, these components are unusual and most components have a component.mk file.

View file

@ -22,9 +22,6 @@ import os
# -- Run DoxyGen to prepare XML for Sphinx--------------------------------- # -- Run DoxyGen to prepare XML for Sphinx---------------------------------
# ref. https://github.com/rtfd/readthedocs.org/issues/388 # ref. https://github.com/rtfd/readthedocs.org/issues/388
#
# added by krzychb, 24-Oct-2016
#
from subprocess import call, Popen, PIPE from subprocess import call, Popen, PIPE
import shlex import shlex
@ -298,8 +295,6 @@ texinfo_documents = [
# -- Use sphinx_rtd_theme for local builds -------------------------------- # -- Use sphinx_rtd_theme for local builds --------------------------------
# ref. https://github.com/snide/sphinx_rtd_theme#using-this-theme-locally-then-building-on-read-the-docs # ref. https://github.com/snide/sphinx_rtd_theme#using-this-theme-locally-then-building-on-read-the-docs
# #
# added by krzychb, 24-Oct-2016
#
# on_rtd is whether we are on readthedocs.org # on_rtd is whether we are on readthedocs.org
on_rtd = os.environ.get('READTHEDOCS', None) == 'True' on_rtd = os.environ.get('READTHEDOCS', None) == 'True'

View file

@ -31,6 +31,7 @@ Contents:
partition-tables partition-tables
build_system build_system
openocd openocd
Secure Boot <security/secure-boot>
.. API Reference .. API Reference
.. ..
@ -92,8 +93,9 @@ Contents:
Wi-Fi <api/esp_wifi> Wi-Fi <api/esp_wifi>
Bluetooth <api/bt> Bluetooth <api/bt>
GPIO <api/gpio> api/gpio
LED Control <api/ledc> api/uart
api/ledc
Logging <api/log> Logging <api/log>
Non-Volatile Storage <api/nvs_flash> Non-Volatile Storage <api/nvs_flash>
@ -114,6 +116,7 @@ Contents:
:maxdepth: 1 :maxdepth: 1
contributing contributing
Style Guide <style-guide>
documenting-code documenting-code
contributor-agreement contributor-agreement

View file

@ -6,6 +6,8 @@ Overview
A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash. A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash.
Partition table length is 0xC00 bytes (maximum 95 partition table entries). If the partition table is signed due to `secure boot`, the signature is appended after the table data.
Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded. Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded.
The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables: The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables:
@ -130,3 +132,6 @@ Flashing the partition table
* ``make flash``: Will flash everything including the partition table. * ``make flash``: Will flash everything including the partition table.
A manual flashing command is also printed as part of ``make partition_table``. A manual flashing command is also printed as part of ``make partition_table``.
.. _secure boot: security/secure-boot.rst

View file

@ -0,0 +1,179 @@
Secure Boot
===========
Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset.
Secure Boot is separate from the Encrypted Flash feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment.
**IMPORTANT: As Encrypted Flash feature and related security features are not yet released, Secure Boot should not be considered sufficient for a secure device and we strongly recommend not enabling the one-time secure bootloader feature until it is mature.**
Background
----------
- Most data is stored in flash. Flash access does not need to be protected from physical access in order for secure boot to function, because critical data is stored (non-software-accessible) in Efuses internal to the chip.
- Efuses are used to store the secure bootloader key (in efuse block 2), and also a single Efuse bit (ABS_DONE_0) is burned (written to 1) to permanently enable secure boot on the chip. For more details about efuse, see the (forthcoming) chapter in the Technical Reference Manual.
- To understand the secure boot process, first familiarise yourself with the standard `esp-idf boot process`.
- Both stages of the boot process (initial software bootloader load, and subsequent partition & app loading) are verified by the secure boot process, in a "chain of trust" relationship.
Secure Boot Process Overview
----------------------------
This is a high level overview of the secure boot process. Step by step instructions are supplied under `How To Enable Secure Boot`. Further in-depth details are supplied under `Technical Details`:
1. The options to enable secure boot are provided in the ``make menuconfig`` hierarchy, under "Secure Boot Configuration".
2. Secure Boot Configuration includes "Secure boot signing key", which is a file path. This file is a ECDSA public/private key pair in a PEM format file.
2. The software bootloader image is built by esp-idf with secure boot support enabled and the public key (signature verification) portion of the secure boot signing key compiled in. This software bootloader image is flashed at offset 0x1000.
3. On first boot, the software bootloader follows the following process to enable secure boot:
- Hardware secure boot support generates a device secure bootloader key (generated via hardware RNG, then stored read/write protected in efuse), and a secure digest. The digest is derived from the key, an IV, and the bootloader image contents.
- The secure digest is flashed at offset 0x0 in the flash.
- Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.)
- Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.)
4. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see `Hardware Secure Boot Support`.
5. When running in secure boot mode, the software bootloader uses the secure boot signing key (the public key of which is embedded in the bootloader itself, and therefore validated as part of the bootloader) to verify the signature appended to all subsequent partition tables and app images before they are booted.
Keys
----
The following keys are used by the secure boot process:
- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see `Re-Flashable Software Bootloader`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled.
- "secure boot signing key" is a standard ECDSA public/private key pair (see `Image Signing Algorithm`) in PEM format.
- The public key from this key pair (for signature verificaton but not signature creation) is compiled into the software bootloader and used to verify the second stage of booting (partition table, app image) before booting continues. The public key can be freely distributed, it does not need to be kept secret.
- The private key from this key pair *must be securely kept private*, as anyone who has this key can authenticate to any bootloader that is configured with secure boot and the matching public key.
How To Enable Secure Boot
-------------------------
1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see `Re-Flashable Software Bootloader`.)
2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet.
3. Set other menuconfig options (as desired). Pay particular attention to the "Bootloader Config" options, as you can only flash the bootloader once. Then exit menuconfig and save your configuration
4. The first time you run ``make``, if the signing key is not found then an error message will be printed with a command to generate a signing key via ``espsecure.py generate_signing_key``.
**IMPORTANT** A signing key generated this way will use the best random number source available to the OS and its Python installation (`/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows). If this random number source is weak, then the private key will be weak.
**IMPORTANT** For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See `Generating Secure Boot Signing Key` for more details.
5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of `make` will include a prompt for a flashing command, using `esptool.py write_flash`.
6. When you're ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. **Remember this is a one time flash, you can't change the bootloader after this!**.
7. Run `make flash` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4.
*NOTE*: `make flash` doesn't flash the bootloader if secure boot is enabled.
8. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occured due to the build configuration.
*NOTE* Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.
9. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed (using the secure bootloader key) and then the software bootloader will verify the signed partition table and app image (using the public key portion of the secure boot signing key).
Re-Flashable Software Bootloader
--------------------------------
Configuration "Secure Boot: One-Time Flash" is the recommended configuration for production devices. In this mode, each device gets a unique key that is never stored outside the device.
However, an alternative mode "Secure Boot: Reflashable" is also available. This mode allows you to supply a 256-bit key file that is used for the secure bootloader key. As you have the key file, you can generate new bootloader images and secure boot digests for them.
In the esp-idf build process, this 256-bit key file is derived from the app signing key generated during the generate_signing_key step above. The private key's SHA-256 digest is used as the 256-bit secure bootloader key. This is a convenience so you only need to generate/protect a single private key.
*NOTE*: Although it's possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments.
To enable a reflashable bootloader:
1. In the ``make menuconfig`` step, select "Bootloader Config" -> "Secure Boot" -> "Reflashable".
2. Follow the steps shown above to choose a signing key file, and generate the key file.
3. Run ``make bootloader``. A 256-bit key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process).
4. Resume from `Step 6<Secure Boot Process Overview>` of the one-time process, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration.
Generating Secure Boot Signing Key
----------------------------------
The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``. This uses the python-ecdsa library, which in turn uses Python's os.urandom() as a random number source.
The strength of the signing key is proportional to (a) the random number source of the system, and (b) the correctness of the algorithm used. For production devices, we recommend generating signing keys from a system with a quality entropy source, and using the best available EC key generation utilities.
For example, to generate a signing key using the openssl command line:
```
openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem
```
Remember that the strength of the secure boot system depends on keeping the signing key private.
Secure Boot Best Practices
--------------------------
* Generate the signing key on a system with a quality source of entropy.
* Keep the signing key private at all times. A leak of this key will compromise the secure boot system.
* Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks.
* Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access.
Technical Details
-----------------
The following sections contain low-level descriptions of various technical functions:
Hardware Secure Boot Support
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Secure Boot support hardware can perform three basic operations:
1. Generate a random sequence of bytes from a hardware random number generator.
2. Generate a digest from data (usually the bootloader image from flash) using a key stored in Efuse block 2. The key in Efuse can (& should) be read/write protected, which prevents software access. For full details of this algorithm see `Secure Bootloader Digest Algorithm`. The digest can only be read back by software if Efuse ABS_DONE_0 is *not* burned (ie still 0).
3. Generate a digest from data (usually the bootloader image from flash) using the same algorithm as step 2 and compare it to a pre-calculated digest supplied in a buffer (usually read from flash offset 0x0). The hardware returns a true/false comparison without making the digest available to software. This function is available even when Efuse ABS_DONE_0 is burned.
Secure Bootloader Digest Algorithm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starting with an "image" of binary data as input, this algorithm generates a digest as output. The digest is sometimes referred to as an "abstract" in hardware documentation.
For a Python version of this algorithm, see the `espsecure.py` tool in the components/esptool_py directory.
Items marked with (^) are to fulfill hardware restrictions, as opposed to cryptographic restrictions.
1. Prefix the image with a 128 byte randomly generated IV.
2. If the image length is not modulo 128, pad the image to a 128 byte boundary with 0xFF. (^)
3. For each 16 byte plaintext block of the input image:
- Reverse the byte order of the plaintext input block (^)
- Apply AES256 in ECB mode to the plaintext block.
- Reverse the byte order of the ciphertext output block. (^)
- Append to the overall ciphertext output.
4. Byte-swap each 4 byte word of the ciphertext (^)
5. Calculate SHA-512 of the ciphertext.
Output digest is 192 bytes of data: The 128 byte IV, followed by the 64 byte SHA-512 digest.
Image Signing Algorithm
~~~~~~~~~~~~~~~~~~~~~~~
Deterministic ECDSA as specified by `RFC6979`.
- Curve is NIST256p (openssl calls this curve "prime256v1", it is also sometimes called secp256r1).
- Hash function is SHA256.
- Key format used for storage is PEM.
- In the bootloader, the public key (for signature verification) is flashed as 64 raw bytes.
- Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data.
.. _esp-idf boot process: ../boot-process.rst
.. _RFC6979: https://tools.ietf.org/html/rfc6979

View file

@ -172,7 +172,7 @@ To re-format a file, run::
Documenting code Documenting code
---------------- ----------------
Please see the guide here: `Documenting Code <documenting-code.rst>`_. Please see the guide here: :doc:`documenting-code`.
Structure and naming Structure and naming
-------------------- --------------------

View file

@ -1,10 +1,5 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main Makefile. This is basically the same as a component makefile.
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
include $(IDF_PATH)/make/component_common.mk

View file

@ -27,6 +27,5 @@ void hello_task(void *pvParameter)
void app_main() void app_main()
{ {
nvs_flash_init(); nvs_flash_init();
system_init();
xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL); xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL);
} }

View file

@ -43,6 +43,5 @@ void blink_task(void *pvParameter)
void app_main() void app_main()
{ {
nvs_flash_init(); nvs_flash_init();
system_init();
xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL); xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL);
} }

View file

@ -1,10 +1,4 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main Makefile. This is basically the same as a component makefile.
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
include $(IDF_PATH)/make/component_common.mk

View file

@ -1,10 +1,4 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main Makefile. This is basically the same as a component makefile.
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
include $(IDF_PATH)/make/component_common.mk

View file

@ -175,7 +175,6 @@ static void http_get_task(void *pvParameters)
void app_main() void app_main()
{ {
nvs_flash_init(); nvs_flash_init();
system_init();
initialise_wifi(); initialise_wifi();
xTaskCreate(&http_get_task, "http_get_task", 2048, NULL, 5, NULL); xTaskCreate(&http_get_task, "http_get_task", 2048, NULL, 5, NULL);
} }

View file

@ -1,44 +0,0 @@
/* This is the CA certificate for the CA trust chain of
www.howsmyssl.com in PEM format, as dumped via:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA cert is the last cert in the chain output by the server.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/*
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
*/
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\r\n"
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\r\n"
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\r\n"
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\r\n"
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n"
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\r\n"
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\r\n"
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\r\n"
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\r\n"
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\r\n"
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\r\n"
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\r\n"
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\r\n"
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\r\n"
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\r\n"
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\r\n"
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\r\n"
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\r\n"
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\r\n"
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\r\n"
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\r\n"
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\r\n"
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\r\n"
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\r\n"
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\r\n"
"-----END CERTIFICATE-----\r\n";

View file

@ -1,10 +1,10 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main Makefile. This is basically the same as a component makefile.
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, # embed files from the "certs" directory as binary data symbols
# please read the ESP-IDF documents if you need to do this. # in the app
# COMPONENT_EMBED_TXTFILES := server_root_cert.pem
include $(IDF_PATH)/make/component_common.mk

View file

@ -74,8 +74,18 @@ static const char *REQUEST = "GET " WEB_URL " HTTP/1.1\n"
"User-Agent: esp-idf/1.0 esp32\n" "User-Agent: esp-idf/1.0 esp32\n"
"\n"; "\n";
/* Root cert for howsmyssl.com, found in cert.c */ /* Root cert for howsmyssl.com, taken from server_root_cert.pem
extern const char *server_root_cert;
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
#ifdef MBEDTLS_DEBUG_C #ifdef MBEDTLS_DEBUG_C
@ -191,7 +201,9 @@ static void https_get_task(void *pvParameters)
ESP_LOGI(TAG, "Loading the CA root certificate..."); ESP_LOGI(TAG, "Loading the CA root certificate...");
ret = mbedtls_x509_crt_parse(&cacert, (uint8_t*)server_root_cert, strlen(server_root_cert)+1); ret = mbedtls_x509_crt_parse(&cacert, server_root_cert_pem_start,
server_root_cert_pem_end-server_root_cert_pem_start);
if(ret < 0) if(ret < 0)
{ {
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
@ -357,7 +369,6 @@ static void https_get_task(void *pvParameters)
void app_main() void app_main()
{ {
nvs_flash_init(); nvs_flash_init();
system_init();
initialise_wifi(); initialise_wifi();
xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL); xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
} }

View file

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -197,10 +197,9 @@ void bleAdvtTask(void *pvParameters)
} }
} }
int app_main() void app_main()
{ {
bt_controller_init(); bt_controller_init();
xTaskCreatePinnedToCore(&bleAdvtTask, "bleAdvtTask", 2048, NULL, 5, NULL, 0); xTaskCreatePinnedToCore(&bleAdvtTask, "bleAdvtTask", 2048, NULL, 5, NULL, 0);
return 0;
} }

View file

@ -1,10 +1,4 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main Makefile. This is basically the same as a component makefile.
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
include $(IDF_PATH)/make/component_common.mk

View file

@ -1,10 +1,4 @@
# #
# Main Makefile. This is basically the same as a component makefile. # Main Makefile. This is basically the same as a component makefile.
# #
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
include $(IDF_PATH)/make/component_common.mk

View file

@ -94,7 +94,6 @@ void app_main()
static void obtain_time(void) static void obtain_time(void)
{ {
nvs_flash_init(); nvs_flash_init();
system_init();
initialise_wifi(); initialise_wifi();
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY); false, true, portMAX_DELAY);

View file

@ -20,9 +20,8 @@ for example in ${IDF_PATH}/examples/*; do
mkdir ${EXAMPLE_NUM} mkdir ${EXAMPLE_NUM}
cp -r ${example} ${EXAMPLE_NUM} cp -r ${example} ${EXAMPLE_NUM}
pushd ${EXAMPLE_NUM}/`basename ${example}` pushd ${EXAMPLE_NUM}/`basename ${example}`
# can't do "make defconfig all" as this will trip menuconfig # build non-verbose first, only build verbose if there's an error
# sometimes make defconfig all || (RESULT=$?; make V=1)
make defconfig && make || RESULT=$?
popd popd
EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 ))
done done

View file

@ -1,12 +1,14 @@
# Functionality common to both top-level project makefile # Functionality common to both top-level project makefile (project.mk)
# and component makefiles # and component makefiles (component_wrapper.mk)
# #
# Include project config file, if it exists. # Include project config makefile, if it exists.
# #
# (Note that we only rebuild auto.conf automatically for some targets, # (Note that we only rebuild this makefile automatically for some
# see project_config.mk for details.) # targets, see project_config.mk for details.)
-include $(BUILD_DIR_BASE)/include/config/auto.conf SDKCONFIG_MAKEFILE ?= $(abspath $(BUILD_DIR_BASE)/include/config/auto.conf)
-include $(SDKCONFIG_MAKEFILE)
export SDKCONFIG_MAKEFILE # sub-makes (like bootloader) will reuse this path
#Handling of V=1/VERBOSE=1 flag #Handling of V=1/VERBOSE=1 flag
# #
@ -14,13 +16,14 @@
# if V is unset or not 1, $(summary) echoes a summary and $(details) does nothing # if V is unset or not 1, $(summary) echoes a summary and $(details) does nothing
V ?= $(VERBOSE) V ?= $(VERBOSE)
ifeq ("$(V)","1") ifeq ("$(V)","1")
Q :=
summary := @true summary := @true
details := @echo details := @echo
else else
Q := @
summary := @echo summary := @echo
details := @true details := @true
# disable echoing of commands, directory names
MAKEFLAGS += --silent
endif endif
# Pseudo-target to check a git submodule has been properly initialised # Pseudo-target to check a git submodule has been properly initialised
@ -34,8 +37,8 @@ endif
define SubmoduleCheck define SubmoduleCheck
$(1): $(1):
@echo "WARNING: Missing submodule $(2) for $$@..." @echo "WARNING: Missing submodule $(2) for $$@..."
$(Q) [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1)
$(Q) [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule --init' in esp-idf root directory."; exit 1) [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule --init' in esp-idf root directory."; exit 1)
@echo "Attempting 'git submodule update --init' in esp-idf root directory..." @echo "Attempting 'git submodule update --init' in esp-idf root directory..."
cd ${IDF_PATH} && git submodule update --init $(2) cd ${IDF_PATH} && git submodule update --init $(2)
@ -53,8 +56,26 @@ endef
# convenience variable for printing an 80 asterisk wide separator line # convenience variable for printing an 80 asterisk wide separator line
SEPARATOR:="*******************************************************************************" SEPARATOR:="*******************************************************************************"
# macro to remove quotes from an argument, ie $(call dequote (CONFIG_BLAH)) # macro to remove quotes from an argument, ie $(call dequote,$(CONFIG_BLAH))
define dequote define dequote
$(subst ",,$(1)) $(subst ",,$(1))
endef endef
# " comment kept here to keep syntax highlighting happy # " comment kept here to keep syntax highlighting happy
# macro to keep an absolute path as-is, but resolve a relative path
# against a particular parent directory
#
# $(1) path to resolve
# $(2) directory to resolve non-absolute path against
#
# Path and directory don't have to exist (definition of a "relative
# path" is one that doesn't start with /)
#
# $(2) can contain a trailing forward slash or not, result will not
# double any path slashes.
#
# example $(call resolvepath,$(CONFIG_PATH),$(CONFIG_DIR))
define resolvepath
$(if $(filter /%,$(1)),$(1),$(subst //,/,$(2)/$(1)))
endef

View file

@ -1,110 +1 @@
# Component common makefile $(warning Deprecated feature: No longer necessary to include component_common.mk from $(COMPONENT_PATH)/component.mk)
#
# This Makefile gets included in the Makefile of all the components to set the correct include paths etc.
# PWD is the build directory of the component and the top Makefile is the one in the
# component source dir.
#
# The way the Makefile differentiates between those two is by looking at the environment
# variable PROJECT_PATH. If this is set (to the basepath of the project), we're building a
# component and its Makefile has included this makefile. If not, we're building the entire project.
#
#
# This Makefile requires the environment variable IDF_PATH to be set
# to the top-level directory where ESP-IDF is located (the directory
# containing this 'make' directory).
#
ifeq ("$(PROJECT_PATH)","")
$(error Make was invoked from $(CURDIR). However please do not run make from the sdk or a component directory; invoke make from the project directory. See the ESP-IDF README for details.)
endif
# Find the path to the component
COMPONENT_PATH := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
export COMPONENT_PATH
include $(IDF_PATH)/make/common.mk
#Some of these options are overridable by the component's component.mk Makefile
#Name of the component
COMPONENT_NAME ?= $(lastword $(subst /, ,$(realpath $(COMPONENT_PATH))))
#Absolute path of the .a file
COMPONENT_LIBRARY := lib$(COMPONENT_NAME).a
#Source dirs a component has. Default to root directory of component.
COMPONENT_SRCDIRS ?= .
#Object files which need to be linked into the library
#By default we take all .c/.S files in the component directory.
ifeq ("$(COMPONENT_OBJS)", "")
#Find all source files in all COMPONENT_SRCDIRS
COMPONENT_OBJS := $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.c,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.c)))
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cpp)))
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.S,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.S)))
#Make relative by removing COMPONENT_PATH from all found object paths
COMPONENT_OBJS := $(patsubst $(COMPONENT_PATH)/%,%,$(COMPONENT_OBJS))
endif
#By default, include only the include/ dir.
COMPONENT_ADD_INCLUDEDIRS ?= include
COMPONENT_ADD_LDFLAGS ?= -l$(COMPONENT_NAME)
#If we're called to compile something, we'll get passed the COMPONENT_INCLUDES
#variable with all the include dirs from all the components in random order. This
#means we can accidentally grab a header from another component before grabbing our own.
#To make sure that does not happen, re-order the includes so ours come first.
OWN_INCLUDES:=$(abspath $(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS) $(COMPONENT_PRIV_INCLUDEDIRS)))
COMPONENT_INCLUDES := $(OWN_INCLUDES) $(filter-out $(OWN_INCLUDES),$(COMPONENT_INCLUDES))
#This target is used to collect variable values from inside project.mk
# see project.mk GetVariable macro for details.
get_variable:
@echo "$(GET_VARIABLE)=$(call $(GET_VARIABLE)) "
#Targets for build/clean. Use builtin recipe if component Makefile
#hasn't defined its own.
ifeq ("$(COMPONENT_OWNBUILDTARGET)", "")
build: $(COMPONENT_LIBRARY)
@mkdir -p $(COMPONENT_SRCDIRS)
#Build the archive. We remove the archive first, otherwise ar will get confused if we update
#an archive when multiple filenames have the same name (src1/test.o and src2/test.o)
$(COMPONENT_LIBRARY): $(COMPONENT_OBJS)
$(summary) AR $@
$(Q) rm -f $@
$(Q) $(AR) cru $@ $(COMPONENT_OBJS)
endif
ifeq ("$(COMPONENT_OWNCLEANTARGET)", "")
clean:
$(summary) RM $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_EXTRA_CLEAN)
$(Q) rm -f $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_EXTRA_CLEAN)
endif
#Include all dependency files already generated
-include $(COMPONENT_OBJS:.o=.d)
#This pattern is generated for each COMPONENT_SRCDIR to compile the files in it.
define GenerateCompileTargets
# $(1) - directory containing source files, relative to $(COMPONENT_PATH)
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.c | $(1)
$$(summary) CC $$@
$$(Q) $$(CC) $$(CFLAGS) $(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp | $(1)
$$(summary) CXX $$@
$$(Q) $$(CXX) $$(CXXFLAGS) $(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S | $(1)
$$(summary) AS $$@
$$(Q) $$(CC) $$(CFLAGS) $(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
# CWD is build dir, create the build subdirectory if it doesn't exist
$(1):
@mkdir -p $(1)
endef
#Generate all the compile target recipes
$(foreach srcdir,$(COMPONENT_SRCDIRS), $(eval $(call GenerateCompileTargets,$(srcdir))))

209
make/component_wrapper.mk Normal file
View file

@ -0,0 +1,209 @@
# Component wrapper makefile
#
# This makefile gets called recursively from the project make, once for each component.
# COMPONENT_MAKEFILE is set to point at the component.mk file for the component itself,
# which is included as part of this process (after default variables are defined).
#
# This makefile comprises multiple stages, marked in blocked comments below.
#
# CWD is the build directory of the component.
ifndef PROJECT_PATH
$(error Make was invoked from $(CURDIR). However please do not run make from the sdk or a component directory; invoke make from the project directory. See the ESP-IDF README for details.)
endif
################################################################################
# 1) Set default variables for the component build (including configuration
# loaded from sdkconfig.)
################################################################################
# Find the path to the component
COMPONENT_PATH := $(abspath $(dir $(COMPONENT_MAKEFILE)))
export COMPONENT_PATH
# COMPONENT_BUILD_DIR is otherwise known as CWD for the build
COMPONENT_BUILD_DIR := $(abspath .)
# include elements common to both project & component makefiles
# (includes project configuration set via menuconfig)
include $(IDF_PATH)/make/common.mk
# Some of the following defaults may be overriden by the component's component.mk makefile,
# during the next step:
# Name of the component
COMPONENT_NAME := $(lastword $(subst /, ,$(realpath $(COMPONENT_PATH))))
# Absolute path of the .a file
COMPONENT_LIBRARY = lib$(COMPONENT_NAME).a
# Source dirs a component has. Default to root directory of component.
COMPONENT_SRCDIRS = .
#Names of binary & text files to embed as raw content in the component library
COMPONENT_EMBED_FILES ?=
COMPONENT_EMBED_TXTFILES ?=
# By default, include only the include/ dir.
COMPONENT_ADD_INCLUDEDIRS = include
COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME)
################################################################################
# 2) Include the component.mk for the specific component (COMPONENT_MAKEFILE) to
# override variables & optionally define custom targets.
################################################################################
include $(COMPONENT_MAKEFILE)
################################################################################
# 3) Set variables that depend on values that may changed by component.mk
################################################################################
# Object files which need to be linked into the library
# By default we take all .c, .cpp & .S files in COMPONENT_SRCDIRS.
ifndef COMPONENT_OBJS
# Find all source files in all COMPONENT_SRCDIRS
COMPONENT_OBJS := $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.c,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.c)))
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cpp)))
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.S,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.S)))
# Make relative by removing COMPONENT_PATH from all found object paths
COMPONENT_OBJS := $(patsubst $(COMPONENT_PATH)/%,%,$(COMPONENT_OBJS))
endif
# Object files with embedded binaries to add to the component library
# Correspond to the files named in COMPONENT_EMBED_FILES & COMPONENT_EMBED_TXTFILES
COMPONENT_EMBED_OBJS ?= $(addsuffix .bin.o,$(COMPONENT_EMBED_FILES)) $(addsuffix .txt.o,$(COMPONENT_EMBED_TXTFILES))
# If we're called to compile something, we'll get passed the COMPONENT_INCLUDES
# variable with all the include dirs from all the components in random order. This
# means we can accidentally grab a header from another component before grabbing our own.
# To make sure that does not happen, re-order the includes so ours come first.
OWN_INCLUDES:=$(abspath $(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS) $(COMPONENT_PRIV_INCLUDEDIRS)))
COMPONENT_INCLUDES := $(OWN_INCLUDES) $(filter-out $(OWN_INCLUDES),$(COMPONENT_INCLUDES))
################################################################################
# 4) Define a target to generate component_project_vars.mk Makefile which
# contains common per-component settings which are included directly in the
# top-level project make
################################################################################
# macro to generate variable-relative paths inside component_project_vars.mk, whenever possible
# ie put literal $(IDF_PATH), $(PROJECT_PATH) and $(BUILD_DIR_BASE) into the generated
# makefiles where possible.
#
# This means if directories move (breaking absolute paths), don't need to 'make clean'
define MakeVariablePath
$(subst $(IDF_PATH),$$(IDF_PATH),$(subst $(PROJECT_PATH),$$(PROJECT_PATH),$(subst $(BUILD_DIR_BASE),\$$(BUILD_DIR_BASE),$(1))))
endef
# component_project_vars.mk target for the component. This is used to
# take component.mk variables COMPONENT_ADD_INCLUDEDIRS,
# COMPONENT_ADD_LDFLAGS and COMPONENT_DEPENDS and inject those into
# the project make pass.
#
# The target here has no dependencies, as the parent target in
# project.mk evaluates dependencies before calling down to here. See
# GenerateComponentTargets macro in project.mk.
#
# If you are thinking of editing the output of this target for a
# component-specific feature, please don't! What you want is a
# Makefile.projbuild for your component (see docs/build-system.rst for
# more.)
component_project_vars.mk::
$(details) "Building component project variables list $(abspath $@)"
@echo '# Automatically generated build file. Do not edit.' > $@
@echo 'COMPONENT_INCLUDES += $(call MakeVariablePath,$(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS)))' >> $@
@echo 'COMPONENT_LDFLAGS += $(call MakeVariablePath,$(COMPONENT_ADD_LDFLAGS))' >> $@
@echo '$(COMPONENT_NAME)-build: $(addsuffix -build,$(COMPONENT_DEPENDS))' >> $@
################################################################################
# 5) If COMPONENT_OWNBUILDTARGET / COMPONENT_OWNCLEANTARGET is not set by component.mk,
# define default build, clean, etc. targets
################################################################################
# If COMPONENT_OWNBUILDTARGET is not set, define a phony build target and
# a COMPONENT_LIBRARY link target.
ifndef COMPONENT_OWNBUILDTARGET
.PHONY: build
build: $(COMPONENT_LIBRARY)
@mkdir -p $(COMPONENT_SRCDIRS)
# Build the archive. We remove the archive first, otherwise ar will get confused if we update
# an archive when multiple filenames have the same name (src1/test.o and src2/test.o)
$(COMPONENT_LIBRARY): $(COMPONENT_OBJS) $(COMPONENT_EMBED_OBJS)
$(summary) AR $@
rm -f $@
$(AR) cru $@ $^
endif
# If COMPONENT_OWNCLEANTARGET is not set, define a phony clean target
ifndef COMPONENT_OWNCLEANTARGET
CLEAN_FILES = $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_EMBED_OBJS) $(COMPONENT_EXTRA_CLEAN) component_project_vars.mk
.PHONY: clean
clean:
$(summary) RM $(CLEAN_FILES)
rm -f $(CLEAN_FILES)
endif
# Include all dependency files already generated
-include $(COMPONENT_OBJS:.o=.d)
# This pattern is generated for each COMPONENT_SRCDIR to compile the files in it.
define GenerateCompileTargets
# $(1) - directory containing source files, relative to $(COMPONENT_PATH)
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.c | $(1)
$$(summary) CC $$@
$$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp | $(1)
$$(summary) CXX $$@
$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S | $(1)
$$(summary) AS $$@
$$(CC) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
# CWD is build dir, create the build subdirectory if it doesn't exist
$(1):
@mkdir -p $(1)
endef
# Generate all the compile target patterns
$(foreach srcdir,$(COMPONENT_SRCDIRS), $(eval $(call GenerateCompileTargets,$(srcdir))))
## Support for embedding binary files into the ELF as symbols
OBJCOPY_EMBED_ARGS := --input binary --output elf32-xtensa-le --binary-architecture xtensa --rename-section .data=.rodata.embedded
# Generate pattern for embedding text or binary files into the app
# $(1) is name of file (as relative path inside component)
# $(2) is txt or bin depending on file contents
#
# txt files are null-terminated before being embedded (otherwise
# identical behaviour.)
#
# Files are temporarily copied to the build directory before objcopy,
# because objcopy generates the symbol name from the full command line
# path to the input file.
define GenerateEmbedTarget
$(1).$(2).o: $(call resolvepath,$(1),$(COMPONENT_PATH)) | $$(dir $(1))
$(summary) EMBED $$@
$$(if $$(filter-out $$(notdir $$(abspath $$<)),$$(abspath $$(notdir $$<))), cp $$< $$(notdir $$<) ) # copy input file to build dir, unless already in build dir
$$(if $$(subst bin,,$(2)),echo -ne '\0' >> $$(notdir $$<) ) # trailing NUL byte on text output
$(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) $$@
rm $$(notdir $$<)
endef
# generate targets to embed binary & text files
$(foreach binfile,$(COMPONENT_EMBED_FILES), $(eval $(call GenerateEmbedTarget,$(binfile),bin)))
$(foreach txtfile,$(COMPONENT_EMBED_TXTFILES), $(eval $(call GenerateEmbedTarget,$(txtfile),txt)))
# generate targets to create binary embed directories
$(foreach bindir,$(sort $(dir $(COMPONENT_EMBED_FILES))), $(eval $(call GenerateBuildDirTarget,$(bindir))))

View file

@ -11,13 +11,13 @@
# #
.PHONY: build-components menuconfig defconfig all build clean all_binaries .PHONY: build-components menuconfig defconfig all build clean all_binaries
all: all_binaries # other components will add dependencies to 'all_binaries' all: all_binaries
@echo "To flash all build output, run 'make flash' or:" # see below for recipe of 'all' target
@echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) #
# # other components will add dependencies to 'all_binaries'. The
# (the reason all_binaries is used instead of 'all' is so that the flash target # reason all_binaries is used instead of 'all' is so that the flash
# can build everything without triggering the per-component "to flash..." # target can build everything without triggering the per-component "to
# output targets.) # flash..." output targets.)
help: help:
@echo "Welcome to Espressif IDF build system. Some useful make targets:" @echo "Welcome to Espressif IDF build system. Some useful make targets:"
@ -36,18 +36,28 @@ help:
@echo "See also 'make bootloader', 'make bootloader-flash', 'make bootloader-clean', " @echo "See also 'make bootloader', 'make bootloader-flash', 'make bootloader-clean', "
@echo "'make partition_table', etc, etc." @echo "'make partition_table', etc, etc."
# dependency checks
ifndef MAKE_RESTARTS
ifeq ("$(filter 4.% 3.81 3.82,$(MAKE_VERSION))","")
$(warning "esp-idf build system only supports GNU Make versions 3.81 or newer. You may see unexpected results with other Makes.")
endif
endif
# disable built-in make rules, makes debugging saner # disable built-in make rules, makes debugging saner
MAKEFLAGS_OLD := $(MAKEFLAGS) MAKEFLAGS_OLD := $(MAKEFLAGS)
MAKEFLAGS +=-rR MAKEFLAGS +=-rR
# Figure out PROJECT_PATH if not set # Default path to the project: we assume the Makefile including this file
ifeq ("$(PROJECT_PATH)","") # is in the project directory
#The path to the project: we assume the Makefile including this file resides ifndef PROJECT_PATH
#in the root of that directory.
PROJECT_PATH := $(abspath $(dir $(firstword $(MAKEFILE_LIST)))) PROJECT_PATH := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
export PROJECT_PATH export PROJECT_PATH
endif endif
# A list of the "common" makefiles, to use as a target dependency
COMMON_MAKEFILES := $(abspath $(IDF_PATH)/make/project.mk $(IDF_PATH)/make/common.mk $(IDF_PATH)/make/component_wrapper.mk)
export COMMON_MAKEFILES
# The directory where we put all objects/libraries/binaries. The project Makefile can # The directory where we put all objects/libraries/binaries. The project Makefile can
# configure this if needed. # configure this if needed.
BUILD_DIR_BASE ?= $(PROJECT_PATH)/build BUILD_DIR_BASE ?= $(PROJECT_PATH)/build
@ -58,82 +68,69 @@ export BUILD_DIR_BASE
COMPONENT_DIRS ?= $(PROJECT_PATH)/components $(EXTRA_COMPONENT_DIRS) $(IDF_PATH)/components COMPONENT_DIRS ?= $(PROJECT_PATH)/components $(EXTRA_COMPONENT_DIRS) $(IDF_PATH)/components
export COMPONENT_DIRS export COMPONENT_DIRS
# Source directories of the project itself (a special, project-specific component.) Defaults to only "main".
SRCDIRS ?= main
# The project Makefile can define a list of components, but if it does not do this we just take # The project Makefile can define a list of components, but if it does not do this we just take
# all available components in the component dirs. # all available components in the component dirs.
ifeq ("$(COMPONENTS)","") ifndef COMPONENTS
# Find all component names. The component names are the same as the # Find all component names. The component names are the same as the
#directories they're in, so /bla/components/mycomponent/ -> mycomponent. We later use # directories they're in, so /bla/components/mycomponent/ -> mycomponent. We then use
#the COMPONENT_DIRS bit to find back the component path. # COMPONENT_DIRS to build COMPONENT_PATHS with the full path to each component.
COMPONENTS := $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/*)) COMPONENTS := $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/*))
COMPONENTS := $(sort $(foreach comp,$(COMPONENTS),$(lastword $(subst /, ,$(comp))))) COMPONENTS := $(sort $(foreach comp,$(COMPONENTS),$(lastword $(subst /, ,$(comp)))))
endif endif
export COMPONENTS export COMPONENTS
#Sources default to only "main" # Resolve all of COMPONENTS into absolute paths in COMPONENT_PATHS.
SRCDIRS ?= main #
# If a component name exists in multiple COMPONENT_DIRS, we take the first match.
#Here, we resolve and add all the components and source paths into absolute paths. #
#If a component exists in multiple COMPONENT_DIRS, we take the first match. # NOTE: These paths must be generated WITHOUT a trailing / so we
#WARNING: These directories paths must be generated WITHOUT a trailing / so we
# can use $(notdir x) to get the component name. # can use $(notdir x) to get the component name.
COMPONENT_PATHS := $(foreach comp,$(COMPONENTS),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp))))) COMPONENT_PATHS := $(foreach comp,$(COMPONENTS),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp)))))
COMPONENT_PATHS += $(abspath $(SRCDIRS)) COMPONENT_PATHS += $(abspath $(SRCDIRS))
#A component is buildable if it has a component.mk makefile; we assume that a # A component is buildable if it has a component.mk makefile in it
# 'make -C $(component dir) -f component.mk build' results in a lib$(componentname).a
COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp))) COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp)))
# Assemble global list of include dirs (COMPONENT_INCLUDES), and # Initialise a project-wide list of include dirs (COMPONENT_INCLUDES),
# LDFLAGS args (COMPONENT_LDFLAGS) supplied by each component. # and LDFLAGS args (COMPONENT_LDFLAGS) supplied by each component.
#
# These variables are built up via the component_project_vars.mk
# generated makefiles (one per component).
COMPONENT_INCLUDES := COMPONENT_INCLUDES :=
COMPONENT_LDFLAGS := COMPONENT_LDFLAGS :=
#
# Also add any inter-component dependencies for each component.
# Extract a variable from a child make process # COMPONENT_PROJECT_VARS is the list of component_project_vars.mk generated makefiles
# for each component.
# #
# $(1) - path to directory to invoke make in # Including $(COMPONENT_PROJECT_VARS) builds the COMPONENT_INCLUDES,
# $(2) - name of variable to print via the get_variable target (passed in GET_VARIABLE) # COMPONENT_LDFLAGS variables and also targets for any inter-component
# dependencies.
# #
# needs 'sed' processing of stdout because make sometimes echoes other stuff on stdout, # See the component_project_vars.mk target in component_wrapper.mk
# even if asked not to. COMPONENT_PROJECT_VARS := $(addsuffix /component_project_vars.mk,$(notdir $(COMPONENT_PATHS_BUILDABLE)))
# COMPONENT_PROJECT_VARS := $(addprefix $(BUILD_DIR_BASE)/,$(COMPONENT_PROJECT_VARS))
# Debugging this? Replace $(shell with $(error and you'll see the full command as-run. # this line is -include instead of include to prevent a spurious error message on make 3.81
define GetVariable -include $(COMPONENT_PROJECT_VARS)
$(shell "$(MAKE)" -s --no-print-directory -C $(1) -f component.mk get_variable PROJECT_PATH=$(PROJECT_PATH) GET_VARIABLE=$(2) | sed -En "s/^$(2)=(.+)/\1/p" )
endef
COMPONENT_INCLUDES := $(abspath $(foreach comp,$(COMPONENT_PATHS_BUILDABLE),$(addprefix $(comp)/, \ # Also add top-level project include path, for top-level includes
$(call GetVariable,$(comp),COMPONENT_ADD_INCLUDEDIRS))))
#Also add project include path, for sdk includes
COMPONENT_INCLUDES += $(abspath $(BUILD_DIR_BASE)/include/) COMPONENT_INCLUDES += $(abspath $(BUILD_DIR_BASE)/include/)
export COMPONENT_INCLUDES export COMPONENT_INCLUDES
#COMPONENT_LDFLAGS has a list of all flags that are needed to link the components together. It's collected # Set variables common to both project & component
#in the same way as COMPONENT_INCLUDES is. include $(IDF_PATH)/make/common.mk
COMPONENT_LDFLAGS := $(foreach comp,$(COMPONENT_PATHS_BUILDABLE), \
$(call GetVariable,$(comp),COMPONENT_ADD_LDFLAGS))
export COMPONENT_LDFLAGS
# Generate component dependency targets from dependencies lists all:
# each component gains a target of its own <name>-build with dependencies ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
# of the names of any other components (-build) that need building first @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
# @echo "To flash app & partition table, run 'make flash' or:"
# the actual targets (that invoke submakes) are generated below by else
# GenerateComponentTarget macro. @echo "To flash all build output, run 'make flash' or:"
define GenerateComponentDependencies endif
# $(1) = component path @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
.PHONY: $$(notdir $(1))
$$(notdir $(1))-build: $(addsuffix -build,$(call GetVariable,$(1),COMPONENT_DEPENDS))
endef
$(foreach comp,$(COMPONENT_PATHS_BUILDABLE), $(eval $(call GenerateComponentDependencies,$(comp))))
#Make sure submakes can also use this.
export PROJECT_PATH
#Include functionality common to both project & component
-include $(IDF_PATH)/make/common.mk
# Set default LDFLAGS # Set default LDFLAGS
@ -142,6 +139,7 @@ LDFLAGS ?= -nostdlib \
-L$(IDF_PATH)/ld \ -L$(IDF_PATH)/ld \
$(addprefix -L$(BUILD_DIR_BASE)/,$(COMPONENTS) $(SRCDIRS)) \ $(addprefix -L$(BUILD_DIR_BASE)/,$(COMPONENTS) $(SRCDIRS)) \
-u call_user_start_cpu0 \ -u call_user_start_cpu0 \
$(EXTRA_LDFLAGS) \
-Wl,--gc-sections \ -Wl,--gc-sections \
-Wl,-static \ -Wl,-static \
-Wl,--start-group \ -Wl,--start-group \
@ -218,7 +216,7 @@ HOSTOBJCOPY := $(OBJCOPY)
export HOSTCC HOSTLD HOSTAR HOSTOBJCOPY export HOSTCC HOSTLD HOSTAR HOSTOBJCOPY
# Set target compiler. Defaults to whatever the user has # Set target compiler. Defaults to whatever the user has
#configured as prefix + yer olde gcc commands # configured as prefix + ye olde gcc commands
CC := $(call dequote,$(CONFIG_TOOLPREFIX))gcc CC := $(call dequote,$(CONFIG_TOOLPREFIX))gcc
CXX := $(call dequote,$(CONFIG_TOOLPREFIX))c++ CXX := $(call dequote,$(CONFIG_TOOLPREFIX))c++
LD := $(call dequote,$(CONFIG_TOOLPREFIX))ld LD := $(call dequote,$(CONFIG_TOOLPREFIX))ld
@ -242,8 +240,12 @@ COMPONENT_PATH := $(1)
endef endef
$(foreach componentpath,$(COMPONENT_PATHS),$(eval $(call includeProjBuildMakefile,$(componentpath)))) $(foreach componentpath,$(COMPONENT_PATHS),$(eval $(call includeProjBuildMakefile,$(componentpath))))
# once we know component paths, we can include the config # once we know component paths, we can include the config generation targets
#
# (bootloader build doesn't need this, config is exported from top-level)
ifndef IS_BOOTLOADER_BUILD
include $(IDF_PATH)/make/project_config.mk include $(IDF_PATH)/make/project_config.mk
endif
# A "component" library is any library in the LDFLAGS where # A "component" library is any library in the LDFLAGS where
# the name of the library is also a name of the component # the name of the library is also a name of the component
@ -254,7 +256,7 @@ COMPONENT_LIBRARIES = $(filter $(notdir $(COMPONENT_PATHS_BUILDABLE)),$(APP_LIBR
# the rules to build these are emitted as part of GenerateComponentTarget below # the rules to build these are emitted as part of GenerateComponentTarget below
$(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp)/lib$(libcomp).a) $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp)/lib$(libcomp).a)
$(summary) LD $(notdir $@) $(summary) LD $(notdir $@)
$(Q) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP)
# Generation of $(APP_BIN) from $(APP_ELF) is added by the esptool # Generation of $(APP_BIN) from $(APP_ELF) is added by the esptool
# component's Makefile.projbuild # component's Makefile.projbuild
@ -267,36 +269,63 @@ all_binaries: $(APP_BIN)
$(BUILD_DIR_BASE): $(BUILD_DIR_BASE):
mkdir -p $(BUILD_DIR_BASE) mkdir -p $(BUILD_DIR_BASE)
define GenerateComponentPhonyTarget # Macro for the recursive sub-make for each component
# $(1) - path to component dir # $(1) - component directory
# $(2) - target to generate (build, clean) # $(2) - component name only
.PHONY: $(notdir $(1))-$(2) #
$(notdir $(1))-$(2): | $(BUILD_DIR_BASE)/$(notdir $(1)) # Is recursively expanded by the GenerateComponentTargets macro
$(Q) +$(MAKE) -C $(BUILD_DIR_BASE)/$(notdir $(1)) -f $(1)/component.mk COMPONENT_BUILD_DIR=$(BUILD_DIR_BASE)/$(notdir $(1)) $(2) define ComponentMake
+$(MAKE) -C $(BUILD_DIR_BASE)/$(2) -f $(IDF_PATH)/make/component_wrapper.mk COMPONENT_MAKEFILE=$(1)/component.mk
endef endef
define GenerateComponentTargets # Generate top-level component-specific targets for each component
# $(1) - path to component dir # $(1) - path to component dir
$(BUILD_DIR_BASE)/$(notdir $(1)): # $(2) - name of component
@mkdir -p $(BUILD_DIR_BASE)/$(notdir $(1)) #
define GenerateComponentTargets
.PHONY: $(2)-build $(2)-clean
# tell make it can build any component's library by invoking the recursive -build target $(2)-build:
$(call ComponentMake,$(1),$(2)) build
$(2)-clean:
$(call ComponentMake,$(1),$(2)) clean
$(BUILD_DIR_BASE)/$(2):
@mkdir -p $(BUILD_DIR_BASE)/$(2)
# tell make it can build any component's library by invoking the -build target
# (this target exists for all components even ones which don't build libraries, but it's # (this target exists for all components even ones which don't build libraries, but it's
# only invoked for the targets whose libraries appear in COMPONENT_LIBRARIES and hence the # only invoked for the targets whose libraries appear in COMPONENT_LIBRARIES and hence the
# APP_ELF dependencies.) # APP_ELF dependencies.)
$(BUILD_DIR_BASE)/$(notdir $(1))/lib$(notdir $(1)).a: $(notdir $(1))-build $(BUILD_DIR_BASE)/$(2)/lib$(2).a: $(2)-build
$(details) "Target '$$^' responsible for '$$@'" # echo which build target built this file $(details) "Target '$$^' responsible for '$$@'" # echo which build target built this file
# add a target to generate the component_project_vars.mk files that
# are used to inject variables into project make pass (see matching
# component_project_vars.mk target in component_wrapper.mk).
#
# If any component_project_vars.mk file is out of date, the make
# process will call this target to rebuild it and then restart.
#
# Note: $(SDKCONFIG) is a normal prereq as we need to rebuild these
# files whenever the config changes. $(SDKCONFIG_MAKEFILE) is an
# order-only prereq because if it hasn't been rebuilt, we need to
# build it first - but including it as a normal prereq can lead to
# infinite restarts as the conf process will keep updating it.
$(BUILD_DIR_BASE)/$(2)/component_project_vars.mk: $(1)/component.mk $(COMMON_MAKEFILES) $(SDKCONFIG) | $(BUILD_DIR_BASE)/$(2) $(SDKCONFIG_MAKEFILE)
$(call ComponentMake,$(1),$(2)) component_project_vars.mk
endef endef
$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentTargets,$(component)))) $(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentTargets,$(component),$(notdir $(component)))))
$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentPhonyTarget,$(component),build)))
$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentPhonyTarget,$(component),clean)))
app-clean: $(addsuffix -clean,$(notdir $(COMPONENT_PATHS_BUILDABLE))) app-clean: $(addsuffix -clean,$(notdir $(COMPONENT_PATHS_BUILDABLE)))
$(summary) RM $(APP_ELF) $(summary) RM $(APP_ELF)
$(Q) rm -f $(APP_ELF) $(APP_BIN) $(APP_MAP) rm -f $(APP_ELF) $(APP_BIN) $(APP_MAP)
clean: app-clean # NB: this ordering is deliberate (app-clean before config-clean),
# so config remains valid during all component clean targets
config-clean: app-clean
clean: config-clean

View file

@ -21,24 +21,28 @@ KCONFIG_TOOL_ENV=KCONFIG_AUTOHEADER=$(abspath $(BUILD_DIR_BASE)/include/sdkconfi
COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" KCONFIG_CONFIG=$(SDKCONFIG) \ COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" KCONFIG_CONFIG=$(SDKCONFIG) \
COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)"
menuconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(BUILD_DIR_BASE) menuconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig
$(summary) MENUCONFIG $(summary) MENUCONFIG
$(Q) $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig
ifeq ("$(wildcard $(SDKCONFIG))","") ifeq ("$(wildcard $(SDKCONFIG))","")
#No sdkconfig found. Need to run menuconfig to make this if we need it. ifeq ("$(filter defconfig,$(MAKECMDGOALS))","")
# if not configuration is present and defconfig is not a target, run makeconfig
$(SDKCONFIG): menuconfig $(SDKCONFIG): menuconfig
else
$(SDKCONFIG): defconfig
endif
endif endif
defconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(BUILD_DIR_BASE) defconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(BUILD_DIR_BASE)
$(summary) DEFCONFIG $(summary) DEFCONFIG
$(Q) mkdir -p $(BUILD_DIR_BASE)/include/config mkdir -p $(BUILD_DIR_BASE)/include/config
$(Q) $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --olddefconfig $(IDF_PATH)/Kconfig $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --olddefconfig $(IDF_PATH)/Kconfig
# Work out of whether we have to build the Kconfig makefile # Work out of whether we have to build the Kconfig makefile
# (auto.conf), or if we're in a situation where we don't need it # (auto.conf), or if we're in a situation where we don't need it
NON_CONFIG_TARGETS := clean %-clean get_variable help menuconfig defconfig NON_CONFIG_TARGETS := clean %-clean help menuconfig defconfig
AUTO_CONF_REGEN_TARGET := $(BUILD_DIR_BASE)/include/config/auto.conf AUTO_CONF_REGEN_TARGET := $(SDKCONFIG_MAKEFILE)
# disable AUTO_CONF_REGEN_TARGET if all targets are non-config targets # disable AUTO_CONF_REGEN_TARGET if all targets are non-config targets
# (and not building default target) # (and not building default target)
@ -46,22 +50,21 @@ ifneq ("$(MAKECMDGOALS)","")
ifeq ($(filter $(NON_CONFIG_TARGETS), $(MAKECMDGOALS)),$(MAKECMDGOALS)) ifeq ($(filter $(NON_CONFIG_TARGETS), $(MAKECMDGOALS)),$(MAKECMDGOALS))
AUTO_CONF_REGEN_TARGET := AUTO_CONF_REGEN_TARGET :=
# dummy target # dummy target
$(BUILD_DIR_BASE)/include/config/auto.conf: $(SDKCONFIG_MAKEFILE):
endif endif
endif endif
$(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(SDKCONFIG) $(KCONFIG_TOOL_DIR)/conf $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) $(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(SDKCONFIG) $(KCONFIG_TOOL_DIR)/conf $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD)
$(summary) GENCONFIG $(summary) GENCONFIG
$(Q) mkdir -p $(BUILD_DIR_BASE)/include/config mkdir -p $(BUILD_DIR_BASE)/include/config
$(Q) cd $(BUILD_DIR_BASE); $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --silentoldconfig $(IDF_PATH)/Kconfig cd $(BUILD_DIR_BASE); $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --silentoldconfig $(IDF_PATH)/Kconfig
$(Q) touch $(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h touch $(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h
# touch to ensure both output files are newer - as 'conf' can also update sdkconfig (a dependency). Without this, # touch to ensure both output files are newer - as 'conf' can also update sdkconfig (a dependency). Without this,
# sometimes you can get an infinite make loop on Windows where sdkconfig always gets regenerated newer # sometimes you can get an infinite make loop on Windows where sdkconfig always gets regenerated newer
# than the target(!) # than the target(!)
clean: config-clean
.PHONY: config-clean .PHONY: config-clean
config-clean: config-clean:
$(summary RM CONFIG) $(summary RM CONFIG)
$(MAKE) -C $(KCONFIG_TOOL_DIR) clean $(MAKE) -C $(KCONFIG_TOOL_DIR) clean
$(Q) rm -rf $(BUILD_DIR_BASE)/include/config $(BUILD_DIR_BASE)/include/sdkconfig.h rm -rf $(BUILD_DIR_BASE)/include/config $(BUILD_DIR_BASE)/include/sdkconfig.h

Some files were not shown because too many files have changed in this diff Show more