From 8d94c1b3cb7ce3c02379305ab065160016f312b9 Mon Sep 17 00:00:00 2001 From: "chenwen@espressif.com" Date: Mon, 23 Oct 2023 17:32:21 +0800 Subject: [PATCH] xtensa/esp32s3: Support malloc from external RAM and internal RAM Enables the allocation of the entire Userspace heap into SPI RAM and reserving the Internal RAM exclusively for the Kernel heap. --- arch/xtensa/include/esp32s3/memory_layout.h | 83 ++++++++ arch/xtensa/src/esp32s3/Kconfig | 23 +++ arch/xtensa/src/esp32s3/Make.defs | 8 + .../xtensa/src/esp32s3/esp32s3_allocateheap.c | 131 +++++++++---- arch/xtensa/src/esp32s3/esp32s3_extraheaps.c | 46 +++++ arch/xtensa/src/esp32s3/esp32s3_imm.c | 183 ++++++++++++++++++ .../esp32s3/common/scripts/legacy_sections.ld | 7 + .../configs/psram_usrheap/defconfig | 57 ++++++ 8 files changed, 505 insertions(+), 33 deletions(-) create mode 100644 arch/xtensa/include/esp32s3/memory_layout.h create mode 100644 arch/xtensa/src/esp32s3/esp32s3_extraheaps.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_imm.c create mode 100644 boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig diff --git a/arch/xtensa/include/esp32s3/memory_layout.h b/arch/xtensa/include/esp32s3/memory_layout.h new file mode 100644 index 0000000000..b5f050ae25 --- /dev/null +++ b/arch/xtensa/include/esp32s3/memory_layout.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/xtensa/include/esp32s3/memory_layout.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The heap overview: + * + * HEAP_REGION0_START g_allocable_vaddr_start + * : + * : g_mmheap (CONFIG_ESP32_SPIRAM) + * : + * HEAP_REGION0_END g_allocable_vaddr_end + * : + *--------------------------------------------------------------------- + * if CONFIG_MM_KERNEL_HEAP && MM_USER_HEAP_IRAM + * + * HEAP_REGION1_START _sheap + * : + * : g_iheap (CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP) + * : + * HEAP_REGION1_START + CONFIG_XTENSA_IMEM_REGION_SIZE + * : + * : g_mmheap region1 + * : + * HEAP_REGION1_END 3fcc fff0 + * : + * HEAP_REGION2_START 3fcd 0000 + * : + * : g_mmheap region2 + * : + * HEAP_REGION2_END dram0_rtos_reserved_start + * : + *--------------------------------------------------------------------- + * if !CONFIG_MM_KERNEL_HEAP || !MM_USER_HEAP_IRAM + * + * HEAP_REGION1_START _sheap + * : + * : g_iheap (CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP) + * : + * HEAP_REGION1_START + CONFIG_XTENSA_IMEM_REGION_SIZE + * : + * : g_mmheap region1 + * : + * HEAP_REGION1_END dram0_rtos_reserved_start + * : + *--------------------------------------------------------------------- + */ + +#ifdef CONFIG_MM_KERNEL_HEAP +#define HEAP_REGION1_END 0x3fccfff0 +#define HEAP_REGION2_START 0x3fcd0000 +#endif + +#ifdef CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP +# define XTENSA_IMEM_REGION_SIZE CONFIG_XTENSA_IMEM_REGION_SIZE +#else +# define XTENSA_IMEM_REGION_SIZE 0 +#endif diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index 72a6caaa4c..f1d8276521 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -861,6 +861,29 @@ config ESP32S3_SPIRAM_IGNORE_NOTFOUND endmenu # SPI RAM Configuration +menu "Memory Configuration" + +comment "Additional Heaps" + +choice ESP32S3_SPIRAM_HEAP + prompt "SPI RAM heap function" + default ESP32S3_SPIRAM_COMMON_HEAP if BUILD_FLAT + default ESP32S3_SPIRAM_USER_HEAP if BUILD_PROTECTED + depends on ESP32S3_SPIRAM + ---help--- + Select how the SPI RAM will be used as heap. + +config ESP32S3_SPIRAM_COMMON_HEAP + bool "Additional region to kernel heap" + +config ESP32S3_SPIRAM_USER_HEAP + bool "Separated userspace heap" + select MM_KERNEL_HEAP + +endchoice # ESP32S3_SPIRAM_HEAP + +endmenu # Memory Configuration + config ESP32S3_GPIO_IRQ bool "GPIO pin interrupts" default n diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs index 54fdbcbbfd..256b7b0551 100644 --- a/arch/xtensa/src/esp32s3/Make.defs +++ b/arch/xtensa/src/esp32s3/Make.defs @@ -144,6 +144,14 @@ CHIP_CSRCS += esp32s3_psram_octal.c endif endif +ifeq ($(CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP),y) +CHIP_CSRCS += esp32s3_imm.c +endif + +ifeq ($(CONFIG_ARCH_HAVE_EXTRA_HEAPS),y) +CHIP_CSRCS += esp32s3_extraheaps.c +endif + ifeq ($(CONFIG_ESP32S3_TOUCH),y) CHIP_CSRCS += esp32s3_touch.c endif diff --git a/arch/xtensa/src/esp32s3/esp32s3_allocateheap.c b/arch/xtensa/src/esp32s3/esp32s3_allocateheap.c index b8d7f48846..05432454c0 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_allocateheap.c +++ b/arch/xtensa/src/esp32s3/esp32s3_allocateheap.c @@ -36,6 +36,7 @@ #include #endif +#include #include "xtensa.h" #include "hardware/esp32s3_rom_layout.h" #ifdef CONFIG_ESP32S3_SPIRAM @@ -46,6 +47,18 @@ * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_MM_KERNEL_HEAP +# if defined(CONFIG_ESP32S3_SPIRAM) +# define MM_USER_HEAP_EXTRAM +# else +# define MM_USER_HEAP_IRAM +# endif + +# define MM_ADDREGION kmm_addregion +#else +# define MM_ADDREGION umm_addregion +#endif + #ifndef ALIGN_DOWN # define ALIGN_DOWN(num, align) ((num) & ~((align) - 1)) #endif @@ -71,43 +84,54 @@ void up_allocate_heap(void **heap_start, size_t *heap_size) { -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) - uintptr_t ubase = USERSPACE->us_dataend; + uintptr_t ubase; + uintptr_t utop; + size_t usize; + +#ifdef CONFIG_MM_KERNEL_HEAP +# ifdef CONFIG_BUILD_PROTECTED + ubase = USERSPACE->us_dataend; /* Align the heap top address to 256 bytes to match the PMS split address * requirement. */ - uintptr_t utop = ALIGN_DOWN(ets_rom_layout_p->dram0_rtos_reserved_start, - 256); - size_t usize = utop - ubase; + utop = ALIGN_DOWN(ets_rom_layout_p->dram0_rtos_reserved_start, 256); + +# elif defined(CONFIG_BUILD_FLAT) +# ifdef MM_USER_HEAP_EXTRAM + ubase = (uintptr_t)esp_spiram_allocable_vaddr_start(); + utop = (uintptr_t)esp_spiram_allocable_vaddr_end(); +# elif defined(MM_USER_HEAP_IRAM) + ubase = (uintptr_t)_sheap + XTENSA_IMEM_REGION_SIZE; + utop = (uintptr_t)HEAP_REGION1_END; +# endif /* MM_USER_HEAP_EXTRAM */ + +# endif /* CONFIG_BUILD_PROTECTED */ + +#else /* !CONFIG_MM_KERNEL_HEAP */ + + /* Skip internal heap region if CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP is + * enabled. + */ + + ubase = (uintptr_t)(_sheap) + XTENSA_IMEM_REGION_SIZE; + utop = (uintptr_t)ets_rom_layout_p->dram0_rtos_reserved_start; +#endif /* CONFIG_MM_KERNEL_HEAP */ + + usize = utop - ubase; minfo("Heap: start=%" PRIxPTR " end=%" PRIxPTR " size=%zu\n", ubase, utop, usize); + DEBUGASSERT(utop > ubase); + board_autoled_on(LED_HEAPALLOCATE); /* Return the userspace heap settings */ *heap_start = (void *)ubase; *heap_size = usize; - - /* Allow user-mode access to the user heap memory in PMP - * is already done in esp32s3_userspace(). - */ - -#else - /* These values come from the linker scripts (esp32s3_sections.ld and - * flat_memory.ld). - * Check boards/xtensa/esp32s3. - */ - - board_autoled_on(LED_HEAPALLOCATE); - - *heap_start = _sheap; - *heap_size = ets_rom_layout_p->dram0_rtos_reserved_start - - (uintptr_t)_sheap; -#endif /* CONFIG_BUILD_PROTECTED && CONFIG_MM_KERNEL_HEAP */ } /**************************************************************************** @@ -122,22 +146,43 @@ void up_allocate_heap(void **heap_start, size_t *heap_size) * ****************************************************************************/ -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) && \ - defined(__KERNEL__) +#ifdef CONFIG_MM_KERNEL_HEAP void up_allocate_kheap(void **heap_start, size_t *heap_size) { + uintptr_t kbase; + uintptr_t ktop; + size_t ksize; + +#ifdef CONFIG_BUILD_PROTECTED /* These values come from the linker scripts (kernel-space.ld and * protected_memory.ld). * Check boards/xtensa/esp32s3. */ - uintptr_t kbase = (uintptr_t)_sheap; - uintptr_t ktop = KDRAM_END; - size_t ksize = ktop - kbase; + kbase = (uintptr_t)_sheap; + ktop = KDRAM_END; +#elif defined(CONFIG_BUILD_FLAT) +# ifdef MM_USER_HEAP_IRAM + /* Skip internal heap region if CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP is + * enabled. + */ + + kbase = (uintptr_t)HEAP_REGION2_START; + ktop = (uintptr_t)ets_rom_layout_p->dram0_rtos_reserved_start; +# else + kbase = (uintptr_t)_sheap + XTENSA_IMEM_REGION_SIZE; + ktop = (uintptr_t)ets_rom_layout_p->dram0_rtos_reserved_start; +# endif /* MM_USER_HEAP_IRAM */ + +#endif + + ksize = ktop - kbase; minfo("Heap: start=%" PRIxPTR " end=%" PRIxPTR " size=%zu\n", kbase, ktop, ksize); + DEBUGASSERT(ktop > kbase); + board_autoled_on(LED_HEAPALLOCATE); *heap_start = (void *)kbase; @@ -157,14 +202,34 @@ void up_allocate_kheap(void **heap_start, size_t *heap_size) #if CONFIG_MM_REGIONS > 1 void xtensa_add_region(void) { -#ifdef CONFIG_ESP32S3_SPIRAM void *start; - size_t size; + void *end; + size_t size = 0; + int availregions = 1; + int nregions = CONFIG_MM_REGIONS - 1; - start = (void *)esp_spiram_allocable_vaddr_start(); - size = (size_t)(esp_spiram_allocable_vaddr_end() - - esp_spiram_allocable_vaddr_start()); - umm_addregion(start, size); +#if defined(CONFIG_ESP32S3_SPIRAM_COMMON_HEAP) && !defined(MM_USER_HEAP_EXTRAM) + availregions++; #endif + + if (nregions < availregions) + { + mwarn("Some memory regions are left unused!\n"); + mwarn("Increase CONFIG_MM_REGIONS to add them to the heap\n"); + } + +#if defined(CONFIG_ESP32S3_SPIRAM_COMMON_HEAP) && !defined(MM_USER_HEAP_EXTRAM) + start = (void *)esp_spiram_allocable_vaddr_start(); + end = (void *)esp_spiram_allocable_vaddr_end(); + size = (size_t)(end - start); +#endif + + if (size) + { + DEBUGASSERT(end > start); + MM_ADDREGION(start, size); + minfo("Heap: start=%" PRIxPTR " end=%" PRIxPTR " size=%zu\n", + (uintptr_t)start, (uintptr_t)end, size); + } } #endif diff --git a/arch/xtensa/src/esp32s3/esp32s3_extraheaps.c b/arch/xtensa/src/esp32s3/esp32s3_extraheaps.c new file mode 100644 index 0000000000..539cfaa402 --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_extraheaps.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_extraheaps.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_extraheaps_init + * + * Description: + * Initialize any extra heap. + * + ****************************************************************************/ + +void up_extraheaps_init(void) +{ +#ifdef CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP + xtensa_imm_initialize(); +#endif +} + diff --git a/arch/xtensa/src/esp32s3/esp32s3_imm.c b/arch/xtensa/src/esp32s3/esp32s3_imm.c new file mode 100644 index 0000000000..0b8f1724ff --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_imm.c @@ -0,0 +1,183 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_imm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "xtensa.h" + +#ifdef CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct mm_heap_s *g_iheap; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: xtensa_imm_initialize + * + * Description: + * Initialize the internal heap. + * + ****************************************************************************/ + +void xtensa_imm_initialize(void) +{ + void *start; + size_t size; + + start = (void *)_sheap; + size = CONFIG_XTENSA_IMEM_REGION_SIZE; + g_iheap = mm_initialize("esp32s3-imem", start, size); +} + +/**************************************************************************** + * Name: xtensa_imm_malloc + * + * Description: + * Allocate memory from the internal heap. + * + ****************************************************************************/ + +void *xtensa_imm_malloc(size_t size) +{ + return mm_malloc(g_iheap, size); +} + +/**************************************************************************** + * Name: xtensa_imm_calloc + * + * Description: + * Calculates the size of the allocation and + * allocate memory the internal heap. + * + ****************************************************************************/ + +void *xtensa_imm_calloc(size_t n, size_t elem_size) +{ + return mm_calloc(g_iheap, n, elem_size); +} + +/**************************************************************************** + * Name: xtensa_imm_realloc + * + * Description: + * Reallocate memory from the internal heap. + * + ****************************************************************************/ + +void *xtensa_imm_realloc(void *ptr, size_t size) +{ + return mm_realloc(g_iheap, ptr, size); +} + +/**************************************************************************** + * Name: xtensa_imm_zalloc + * + * Description: + * Allocate and zero memory from the internal heap. + * + ****************************************************************************/ + +void *xtensa_imm_zalloc(size_t size) +{ + return mm_zalloc(g_iheap, size); +} + +/**************************************************************************** + * Name: xtensa_imm_free + * + * Description: + * Free memory from the internal heap. + * + ****************************************************************************/ + +void xtensa_imm_free(void *mem) +{ + mm_free(g_iheap, mem); +} + +/**************************************************************************** + * Name: xtensa_imm_memalign + * + * Description: + * memalign requests more than enough space from malloc, finds a region + * within that chunk that meets the alignment request and then frees any + * leading or trailing space. + * + * The alignment argument must be a power of two (not checked). 8-byte + * alignment is guaranteed by normal malloc calls. + * + ****************************************************************************/ + +void *xtensa_imm_memalign(size_t alignment, size_t size) +{ + return mm_memalign(g_iheap, alignment, size); +} + +/**************************************************************************** + * Name: xtensa_imm_heapmember + * + * Description: + * Check if an address lies in the internal heap. + * + * Parameters: + * mem - The address to check + * + * Return Value: + * true if the address is a member of the internal heap. false if not + * + ****************************************************************************/ + +bool xtensa_imm_heapmember(void *mem) +{ + return mm_heapmember(g_iheap, mem); +} + +/**************************************************************************** + * Name: xtensa_imm_mallinfo + * + * Description: + * mallinfo returns a copy of updated current heap information for the + * user heap. + * + ****************************************************************************/ + +struct mallinfo xtensa_imm_mallinfo(void) +{ + return mm_mallinfo(g_iheap); +} + +#endif /* CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP */ diff --git a/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld b/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld index 4324f61818..a6690168bb 100644 --- a/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld +++ b/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld @@ -124,6 +124,13 @@ SECTIONS *libc.a:sq_remfirst.*(.literal.sq_remfirst .text.sq_remfirst) #endif + *libarch.a:esp32s3_spi_timing.*(.literal .text .literal.* .text.*) +#ifdef CONFIG_ESP32S3_SPIRAM_MODE_QUAD + *libarch.a:esp32s3_psram_quad.*(.literal .text .literal.* .text.*) +#endif +#ifdef CONFIG_ESP32S3_SPIRAM_MODE_OCT + *libarch.a:esp32s3_psram_octal.*(.literal .text .literal.* .text.*) +#endif *(.wifirxiram .wifirxiram.*) *(.wifi0iram .wifi0iram.*) *(.wifiorslpiram .wifiorslpiram.*) diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig b/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig new file mode 100644 index 0000000000..de2e2cb130 --- /dev/null +++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig @@ -0,0 +1,57 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="xtensa" +CONFIG_ARCH_BOARD="esp32s3-devkit" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32S3_DEVKIT=y +CONFIG_ARCH_CHIP="esp32s3" +CONFIG_ARCH_CHIP_ESP32S3=y +CONFIG_ARCH_CHIP_ESP32S3WROOM1=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_XTENSA=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_ESP32S3_FLASH_FREQ_80M=y +CONFIG_ESP32S3_SPIRAM=y +CONFIG_ESP32S3_SPIRAM_MODE_OCT=y +CONFIG_ESP32S3_SPIRAM_USER_HEAP=y +CONFIG_ESP32S3_UART0=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_NBUFFERS=36 +CONFIG_IOB_NCHAINS=36 +CONFIG_IOB_THROTTLE=8 +CONFIG_MM_IOB=y +CONFIG_MM_REGIONS=2 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_SYSLOG_BUFFER=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_MM=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y