From 0db8b00b8aced2367d9226bccb1fa5210d034733 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 25 Jan 2017 17:25:50 +0800 Subject: [PATCH 1/6] tight 28k --- components/esp32/cpu_start.c | 15 +- components/esp32/heap_alloc_caps.c | 45 ++- .../esp32/include/esp_heap_alloc_caps.h | 11 + components/esp32/include/heap_alloc_caps.h | 34 -- components/esp32/ld/esp32.rom.ld | 343 +++++++++--------- 5 files changed, 243 insertions(+), 205 deletions(-) delete mode 100644 components/esp32/include/heap_alloc_caps.h diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index cf20083508..2dbfffd5a2 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -38,7 +38,7 @@ #include "tcpip_adapter.h" -#include "heap_alloc_caps.h" +#include "esp_heap_alloc_caps.h" #include "sdkconfig.h" #include "esp_system.h" #include "esp_spi_flash.h" @@ -106,8 +106,6 @@ void IRAM_ATTR call_start_cpu0() memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); } - // Initialize heap allocator - heap_alloc_caps_init(); ESP_EARLY_LOGI(TAG, "Pro cpu up."); @@ -131,6 +129,15 @@ void IRAM_ATTR call_start_cpu0() ESP_EARLY_LOGI(TAG, "Single core mode"); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); #endif + + /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted. + If the heap allocator is initialized first, it will put free memory linked list items into + memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory, + corrupting those linked lists. Initializing the allocator *after* the app cpu has booted + works around this problem. */ + heap_alloc_caps_init(); + + ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); start_cpu0(); } @@ -250,6 +257,8 @@ static void main_task(void* args) // Now that the application is about to start, disable boot watchdogs REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S); REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); + //Enable allocation in region where the startup stacks were located. + heap_alloc_enable_nonos_stack_tag(); app_main(); vTaskDelete(NULL); } diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 7d2a26e64e..565dd9b8fd 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -36,6 +36,7 @@ hardwiring addresses. //Amount of priority slots for the tag descriptors. #define NO_PRIOS 3 + typedef struct { const char *name; uint32_t prio[NO_PRIOS]; @@ -46,6 +47,9 @@ typedef struct { Tag descriptors. These describe the capabilities of a bit of memory that's tagged with the index into this table. Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request. Make sure there are never more than HEAPREGIONS_MAX_TAGCOUNT (in heap_regions.h) tags (ex the last empty marker) + +WARNING: The current code assumes the ROM stacks are located in tag 1; no allocation from this tag can be done until +the FreeRTOS scheduler has started. */ static const tag_desc_t tag_desc[]={ { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, false}, //Tag 0: Plain ole D-port RAM @@ -89,8 +93,8 @@ This array is *NOT* const because it gets modified depending on what pools are/a static HeapRegionTagged_t regions[]={ { (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available { (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code - { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT - { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT + { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- if BT is enabled, used as BT HW shared memory + { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- if BT is enabled, used data memory for BT ROM functions. { (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0 { (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1 { (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2 @@ -134,6 +138,16 @@ static HeapRegionTagged_t regions[]={ { NULL, 0, 0, 0} //end }; +/* For the startup code, the stacks live in memory tagged by this tag. Hence, we only enable allocating from this tag + once FreeRTOS has started up completely. */ +#define NONOS_STACK_TAG 1 + +static bool nonos_stack_in_use=true; + +void heap_alloc_enable_nonos_stack_tag() +{ + nonos_stack_in_use=false; +} //Modify regions array to disable the given range of memory. static void disable_mem_region(void *from, void *to) { @@ -185,12 +199,24 @@ void heap_alloc_caps_init() { //Disable the bits of memory where this code is loaded. disable_mem_region(&_data_start, &_heap_start); //DRAM used by bss/data static variables disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code - disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region - // TODO: this region should be checked, since we don't need to knock out all region finally - disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region + /* Warning: The ROM stack is located in the 0x3ffe0000 area. We do not specifically disable that area here because + after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing + any mallocs from tag 1 (the IRAM/DRAM region) until the scheduler has started. + + The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines knocks + out the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are + not usable in FreeRTOS anyway, are commented out in the linker script so they cannot be used; we + do not disable their memory regions here and they will be used as general purpose heap memory. + + Enabling the heap allocator for this region but disabling allocation here until FreeRTOS is started up + is a somewhat risky action in theory, because on initializing the allocator, it will go and write linked + list entries at the start and end of all regions. For the ESP32, these linked list entries happen to end + up in a region that is not touched by the stack; they can be placed safely there.*/ + disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //knock out ROM PRO data region + disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //knock out ROM APP data region #if CONFIG_BT_ENABLED #if CONFIG_BT_DRAM_RELEASE @@ -198,8 +224,11 @@ void heap_alloc_caps_init() { disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //knock out BT data region disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //knock out BT data region #else - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT hardware shared memory & BT data region #endif + disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //knock out ROM data region, inc region needed for BT ROM routines +#else + disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //knock out ROM data region #endif #if CONFIG_MEMMAP_TRACEMEM @@ -317,6 +346,10 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) for (prio=0; prio>>>> btdm data */ + From e5f54a9dbdb117df3132726de5304ed08a591450 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 25 Jan 2017 17:46:26 +0800 Subject: [PATCH 2/6] Validate more GPIO ROM functions for non-use of static RAM --- components/esp32/ld/esp32.rom.ld | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 05687e2df9..bed42c988a 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1677,21 +1677,11 @@ replace them and this way we can re-use the fixed RAM addresses these routines n */ /* PROVIDE ( gpio_init = 0x40009c20 ); -PROVIDE ( gpio_input_get = 0x40009b88 ); -PROVIDE ( gpio_input_get_high = 0x40009b9c ); PROVIDE ( gpio_intr_ack = 0x40009dd4 ); PROVIDE ( gpio_intr_ack_high = 0x40009e1c ); PROVIDE ( gpio_intr_handler_register = 0x40009e6c ); PROVIDE ( gpio_intr_pending = 0x40009cec ); PROVIDE ( gpio_intr_pending_high = 0x40009cf8 ); -PROVIDE ( gpio_matrix_in = 0x40009edc ); -PROVIDE ( gpio_matrix_out = 0x40009f0c ); -PROVIDE ( gpio_pad_hold = 0x4000a734 ); -PROVIDE ( gpio_pad_pulldown = 0x4000a348 ); -PROVIDE ( gpio_pad_pullup = 0x4000a22c ); -PROVIDE ( gpio_pad_select_gpio = 0x40009fdc ); -PROVIDE ( gpio_pad_set_drv = 0x4000a11c ); -PROVIDE ( gpio_pad_unhold = 0x4000a484 ); PROVIDE ( gpio_pending_mask = 0x3ffe0038 ); PROVIDE ( gpio_pending_mask_high = 0x3ffe0044 ); PROVIDE ( gpio_pin_intr_state_set = 0x40009d04 ); @@ -1703,6 +1693,16 @@ PROVIDE ( gpio_register_set = 0x40009bbc ); /* These are still part of that driver, but have been verified not to use static RAM, so they can be used. */ PROVIDE ( gpio_output_set = 0x40009b24 ); PROVIDE ( gpio_output_set_high = 0x40009b5c ); +PROVIDE ( gpio_input_get = 0x40009b88 ); +PROVIDE ( gpio_input_get_high = 0x40009b9c ); +PROVIDE ( gpio_matrix_in = 0x40009edc ); +PROVIDE ( gpio_matrix_out = 0x40009f0c ); +PROVIDE ( gpio_pad_select_gpio = 0x40009fdc ); +PROVIDE ( gpio_pad_set_drv = 0x4000a11c ); +PROVIDE ( gpio_pad_pulldown = 0x4000a348 ); +PROVIDE ( gpio_pad_pullup = 0x4000a22c ); +PROVIDE ( gpio_pad_hold = 0x4000a734 ); +PROVIDE ( gpio_pad_unhold = 0x4000a484 ); /* These functions are part of the non-os kernel (etsc). From 37d56b0e8a6c9e032835926ee93df2cb6c75da43 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 27 Jan 2017 15:01:51 +0800 Subject: [PATCH 3/6] Add small testcase --- components/freertos/test/test_malloc.c | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 components/freertos/test/test_malloc.c diff --git a/components/freertos/test/test_malloc.c b/components/freertos/test/test_malloc.c new file mode 100644 index 0000000000..d7f1464508 --- /dev/null +++ b/components/freertos/test/test_malloc.c @@ -0,0 +1,49 @@ +/* + Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc. +*/ + +#include +#include +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" +#include "unity.h" +#include "soc/uart_reg.h" +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" + +static int tryAllocMem() { + int **mem; + int i, noAllocated, j; + mem=malloc(sizeof(int)*1024); + if (!mem) return 0; + for (i=0; i<1024; i++) { + mem[i]=malloc(1024); + if (mem[i]==NULL) break; + for (j=0; j<1024/4; j++) mem[i][j]=(0xdeadbeef); + } + noAllocated=i; + for (i=0; i Date: Wed, 8 Mar 2017 19:27:30 +0800 Subject: [PATCH 4/6] MR suggestions --- components/esp32/heap_alloc_caps.c | 20 ++++++++++---------- components/esp32/include/heap_alloc_caps.h | 3 +++ components/esp32/ld/esp32.rom.ld | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 components/esp32/include/heap_alloc_caps.h diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 565dd9b8fd..6597ca7f07 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -215,27 +215,27 @@ void heap_alloc_caps_init() { is a somewhat risky action in theory, because on initializing the allocator, it will go and write linked list entries at the start and end of all regions. For the ESP32, these linked list entries happen to end up in a region that is not touched by the stack; they can be placed safely there.*/ - disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //knock out ROM PRO data region - disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //knock out ROM APP data region + disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //Reserve ROM PRO data region + disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //Reserve ROM APP data region #if CONFIG_BT_ENABLED #if CONFIG_BT_DRAM_RELEASE - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffb3000); //knock out BT data region - disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //knock out BT data region - disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //knock out BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffb3000); //Reserve BT data region + disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //Reserve BT data region + disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //Reserve BT data region #else - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT hardware shared memory & BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //Reserve BT hardware shared memory & BT data region #endif - disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //knock out ROM data region, inc region needed for BT ROM routines + disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //Reserve ROM data region, inc region needed for BT ROM routines #else - disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //knock out ROM data region + disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //Reserve ROM data region #endif #if CONFIG_MEMMAP_TRACEMEM #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS - disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region + disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //Reserve trace mem region #else - disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //knock out trace mem region + disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //Reserve trace mem region #endif #endif diff --git a/components/esp32/include/heap_alloc_caps.h b/components/esp32/include/heap_alloc_caps.h new file mode 100644 index 0000000000..edab15d52d --- /dev/null +++ b/components/esp32/include/heap_alloc_caps.h @@ -0,0 +1,3 @@ +#pragma once +#warning heap_alloc_caps.h has been renamed to esp_heap_alloc_caps.h. The old header file is deprecated and will be removed in v3.0. +#include "esp_heap_alloc_caps.h" diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index bed42c988a..6cbd2fc747 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1675,7 +1675,7 @@ PROVIDE ( uart_tx_wait_idle = 0x40009278 ); These functions are part of the ROM GPIO driver. We do not use them; the provided esp-idf functions replace them and this way we can re-use the fixed RAM addresses these routines need. */ -/* +/* <-- So you don't read over it: This comment disables the next lines. PROVIDE ( gpio_init = 0x40009c20 ); PROVIDE ( gpio_intr_ack = 0x40009dd4 ); PROVIDE ( gpio_intr_ack_high = 0x40009e1c ); From ab5bbfa74bed2bef28ad62e14b64a26b3ef51b34 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 8 Mar 2017 19:44:57 +0800 Subject: [PATCH 5/6] Malloc test: tabs -> spaces, fix description --- components/freertos/test/test_malloc.c | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/components/freertos/test/test_malloc.c b/components/freertos/test/test_malloc.c index d7f1464508..7bcc291e30 100644 --- a/components/freertos/test/test_malloc.c +++ b/components/freertos/test/test_malloc.c @@ -1,5 +1,5 @@ /* - Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc. + Generic test for malloc/free */ #include @@ -17,33 +17,33 @@ #include "soc/io_mux_reg.h" static int tryAllocMem() { - int **mem; - int i, noAllocated, j; - mem=malloc(sizeof(int)*1024); - if (!mem) return 0; - for (i=0; i<1024; i++) { - mem[i]=malloc(1024); - if (mem[i]==NULL) break; - for (j=0; j<1024/4; j++) mem[i][j]=(0xdeadbeef); - } - noAllocated=i; - for (i=0; i Date: Thu, 9 Mar 2017 19:59:09 +0800 Subject: [PATCH 6/6] MR things --- components/esp32/heap_alloc_caps.c | 10 +++++----- components/esp32/include/esp_heap_alloc_caps.h | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 6597ca7f07..1c6df9491b 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -206,15 +206,15 @@ void heap_alloc_caps_init() { after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing any mallocs from tag 1 (the IRAM/DRAM region) until the scheduler has started. - The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines knocks - out the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are + The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines + reserve the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are not usable in FreeRTOS anyway, are commented out in the linker script so they cannot be used; we do not disable their memory regions here and they will be used as general purpose heap memory. Enabling the heap allocator for this region but disabling allocation here until FreeRTOS is started up - is a somewhat risky action in theory, because on initializing the allocator, it will go and write linked - list entries at the start and end of all regions. For the ESP32, these linked list entries happen to end - up in a region that is not touched by the stack; they can be placed safely there.*/ + is a somewhat risky action in theory, because on initializing the allocator, vPortDefineHeapRegionsTagged + will go and write linked list entries at the start and end of all regions. For the ESP32, these linked + list entries happen to end up in a region that is not touched by the stack; they can be placed safely there.*/ disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //Reserve ROM PRO data region disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //Reserve ROM APP data region diff --git a/components/esp32/include/esp_heap_alloc_caps.h b/components/esp32/include/esp_heap_alloc_caps.h index 7a9844d16e..e1021c30b1 100644 --- a/components/esp32/include/esp_heap_alloc_caps.h +++ b/components/esp32/include/esp_heap_alloc_caps.h @@ -41,9 +41,10 @@ void heap_alloc_caps_init(); /** * @brief Enable the memory region where the startup stacks are located for allocation * - * On startup, the pro/app CPUs have a certain stack frame, so we cannot do allocations - * in the regions these stack frames are. When FreeRTOS is completely started, they do - * not use that memory anymore and allocation there can be re-enabled. + * On startup, the pro/app CPUs have a certain memory region they use as stack, so we + * cannot do allocations in the regions these stack frames are. When FreeRTOS is + * completely started, they do not use that memory anymore and allocation there can + * be re-enabled. */ void heap_alloc_enable_nonos_stack_tag();