From 1f1d90de1c5f1ffa2675e16ca8468461f766cd96 Mon Sep 17 00:00:00 2001 From: dongjiuzhu1 Date: Wed, 29 Nov 2023 22:25:47 +0800 Subject: [PATCH] binfmt/modlib: support loading each sections to different memory for Relocate object The feature depends on ARCH_USE_SEPARATED_SECTION the different memory area has different access speed and cache capability, so the arch can custom allocate them based on section names to achieve performance optimization test: sim:elf sim:sotest Signed-off-by: dongjiuzhu1 --- arch/Kconfig | 8 + arch/sim/src/Makefile | 2 +- arch/sim/src/sim/CMakeLists.txt | 2 +- .../sim/{sim_textheap.c => sim_sectionheap.c} | 60 ++++++- binfmt/binfmt_unloadmodule.c | 33 ++++ binfmt/elf.c | 16 ++ binfmt/libelf/libelf_addrenv.c | 62 ++++++-- binfmt/libelf/libelf_bind.c | 24 ++- binfmt/libelf/libelf_load.c | 105 +++++++++++- include/nuttx/arch.h | 14 +- include/nuttx/binfmt/binfmt.h | 4 + include/nuttx/binfmt/elf.h | 4 + include/nuttx/lib/modlib.h | 4 + libs/libc/dlfcn/lib_dlopen.c | 8 + libs/libc/modlib/modlib_bind.c | 24 ++- libs/libc/modlib/modlib_load.c | 149 +++++++++++++++--- libs/libc/modlib/modlib_unload.c | 28 ++++ sched/module/mod_insmod.c | 8 + 18 files changed, 507 insertions(+), 48 deletions(-) rename arch/sim/src/sim/{sim_textheap.c => sim_sectionheap.c} (63%) diff --git a/arch/Kconfig b/arch/Kconfig index c4c095ddcc..4d94cbf40a 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -671,6 +671,14 @@ config ARCH_USE_DATA_HEAP This option enables architecture-specific memory allocator for dynamic data loading. +config ARCH_USE_SEPARATED_SECTION + bool "Enable separate section allocation for dynamic loading" + default n + depends on ARCH_USE_TEXT_HEAP || ARCH_USE_DATA_HEAP + ---help--- + This option enables loading different sections into different + memory areas, allowing for different speeds. + menuconfig ARCH_ADDRENV bool "Address environments" default n diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index a2632b38e2..2f25984ed4 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -81,7 +81,7 @@ CSRCS = sim_initialize.c sim_idle.c sim_doirq.c sim_initialstate.c CSRCS += sim_createstack.c sim_usestack.c sim_releasestack.c sim_stackframe.c CSRCS += sim_exit.c sim_schedulesigaction.c sim_switchcontext.c sim_heap.c CSRCS += sim_uart.c sim_copyfullstate.c sim_sigdeliver.c sim_tcbinfo.c sim_cpuinfo.c -CSRCS += sim_registerdump.c sim_saveusercontext.c sim_textheap.c +CSRCS += sim_registerdump.c sim_saveusercontext.c sim_sectionheap.c CSRCS += sim_checkhostfstypes.c ifeq ($(CONFIG_SCHED_BACKTRACE),y) diff --git a/arch/sim/src/sim/CMakeLists.txt b/arch/sim/src/sim/CMakeLists.txt index ccd91cfc9b..a4e114b147 100644 --- a/arch/sim/src/sim/CMakeLists.txt +++ b/arch/sim/src/sim/CMakeLists.txt @@ -57,7 +57,7 @@ list( sim_registerdump.c sim_saveusercontext.c sim_tcbinfo.c - sim_textheap.c + sim_sectionheap.c sim_checkhostfstypes.c) if(CONFIG_HOST_X86_64) diff --git a/arch/sim/src/sim/sim_textheap.c b/arch/sim/src/sim/sim_sectionheap.c similarity index 63% rename from arch/sim/src/sim/sim_textheap.c rename to arch/sim/src/sim/sim_sectionheap.c index 6fa233201e..411190b51b 100644 --- a/arch/sim/src/sim/sim_textheap.c +++ b/arch/sim/src/sim/sim_sectionheap.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/sim/src/sim/sim_textheap.c + * arch/sim/src/sim/sim_sectionheap.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -32,6 +32,7 @@ ****************************************************************************/ static struct mm_heap_s *g_textheap; +static struct mm_heap_s *g_dataheap; /**************************************************************************** * Public Functions @@ -45,7 +46,11 @@ static struct mm_heap_s *g_textheap; * ****************************************************************************/ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION +void *up_textheap_memalign(const char *sectname, size_t align, size_t size) +#else void *up_textheap_memalign(size_t align, size_t size) +#endif { if (g_textheap == NULL) { @@ -85,3 +90,56 @@ bool up_textheap_heapmember(void *p) { return g_textheap != NULL && mm_heapmember(g_textheap, p); } + +/**************************************************************************** + * Name: up_dataheap_memalign + * + * Description: + * Allocate memory for data sections with the specified alignment. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION +void *up_dataheap_memalign(const char *sectname, size_t align, size_t size) +#else +void *up_dataheap_memalign(size_t align, size_t size) +#endif +{ + if (g_dataheap == NULL) + { + g_dataheap = mm_initialize("dataheap", + host_allocheap(SIM_HEAP_SIZE, true), + SIM_HEAP_SIZE); + } + + return mm_memalign(g_dataheap, align, size); +} + +/**************************************************************************** + * Name: up_dataheap_free + * + * Description: + * Free memory allocated for data sections. + * + ****************************************************************************/ + +void up_dataheap_free(void *p) +{ + if (g_dataheap != NULL) + { + mm_free(g_dataheap, p); + } +} + +/**************************************************************************** + * Name: up_dataheap_heapmember + * + * Description: + * Test if memory is from data heap. + * + ****************************************************************************/ + +bool up_dataheap_heapmember(void *p) +{ + return g_dataheap != NULL && mm_heapmember(g_dataheap, p); +} diff --git a/binfmt/binfmt_unloadmodule.c b/binfmt/binfmt_unloadmodule.c index b15fc4c69c..bc5effded8 100644 --- a/binfmt/binfmt_unloadmodule.c +++ b/binfmt/binfmt_unloadmodule.c @@ -161,6 +161,32 @@ int unload_module(FAR struct binary_s *binp) file_munmap(binp->mapped, binp->mapsize); } +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + for (i = 0; binp->sectalloc[i] != NULL && i < binp->nsect; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(binp->sectalloc[i])) + { + up_textheap_free(binp->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember(binp->sectalloc[i])) + { + up_dataheap_free(binp->sectalloc[i]); + continue; + } +# endif + + kumm_free(binp->sectalloc[i]); + } + + binp->alloc[0] = NULL; + binp->alloc[1] = NULL; +#endif + /* Free allocated address spaces */ for (i = 0; i < BINFMT_NALLOC; i++) @@ -174,6 +200,13 @@ int unload_module(FAR struct binary_s *binp) up_textheap_free(binp->alloc[i]); } else +#endif +#if defined(CONFIG_ARCH_USE_DATA_HEAP) + if (i == 1) + { + up_dataheap_free(binp->alloc[i]); + } + else #endif { kumm_free(binp->alloc[i]); diff --git a/binfmt/elf.c b/binfmt/elf.c index 5e3ed98380..1ea77cea3f 100644 --- a/binfmt/elf.c +++ b/binfmt/elf.c @@ -164,6 +164,14 @@ static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo) for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + binfo("Sections %d:\n", i); binfo(" sh_name: %08x\n", shdr->sh_name); binfo(" sh_type: %08x\n", shdr->sh_type); @@ -317,6 +325,14 @@ static int elf_loadbinary(FAR struct binary_s *binp, binp->addrenv = loadinfo.addrenv; #else +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo.ehdr.e_type == ET_REL) + { + binp->sectalloc = (FAR void *)loadinfo.sectalloc; + binp->nsect = loadinfo.ehdr.e_shnum; + } +# endif + binp->alloc[0] = (FAR void *)loadinfo.textalloc; binp->alloc[1] = (FAR void *)loadinfo.dataalloc; # ifdef CONFIG_BINFMT_CONSTRUCTORS diff --git a/binfmt/libelf/libelf_addrenv.c b/binfmt/libelf/libelf_addrenv.c index 944981b408..3f2ebe3b66 100644 --- a/binfmt/libelf/libelf_addrenv.c +++ b/binfmt/libelf/libelf_addrenv.c @@ -146,13 +146,15 @@ errout_with_addrenv: /* Allocate memory to hold the ELF image */ -# if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# ifndef CONFIG_ARCH_USE_SEPARATED_SECTION +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) loadinfo->textalloc = (uintptr_t) - up_textheap_memalign(loadinfo->textalign, textsize); -# else + up_textheap_memalign(loadinfo->textalign, + textsize); +# else loadinfo->textalloc = (uintptr_t) kumm_memalign(loadinfo->textalign, textsize); -# endif +# endif if (!loadinfo->textalloc) { @@ -161,19 +163,20 @@ errout_with_addrenv: if (loadinfo->datasize > 0) { -# if defined(CONFIG_ARCH_USE_DATA_HEAP) +# ifdef CONFIG_ARCH_USE_DATA_HEAP loadinfo->dataalloc = (uintptr_t) up_dataheap_memalign(loadinfo->dataalign, datasize); -# else +# else loadinfo->dataalloc = (uintptr_t) kumm_memalign(loadinfo->dataalign, datasize); -# endif +# endif if (!loadinfo->dataalloc) { return -ENOMEM; } } +# endif return OK; #endif @@ -290,23 +293,56 @@ void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo) addrenv_drop(loadinfo->addrenv, false); #else +# ifndef CONFIG_ARCH_USE_SEPARATED_SECTION if (loadinfo->textalloc != 0) { -# if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) up_textheap_free((FAR void *)loadinfo->textalloc); -# else +# else kumm_free((FAR void *)loadinfo->textalloc); -# endif +# endif } if (loadinfo->dataalloc != 0) { -# if defined(CONFIG_ARCH_USE_DATA_HEAP) +# if defined(CONFIG_ARCH_USE_DATA_HEAP) up_dataheap_free((FAR void *)loadinfo->dataalloc); -# else +# else kumm_free((FAR void *)loadinfo->dataalloc); -# endif +# endif } +# else + int i; + + for (i = 0; loadinfo->ehdr.e_type == ET_REL && i < loadinfo->ehdr.e_shnum; + i++) + { + if (loadinfo->sectalloc[i] == 0) + { + continue; + } + + if ((loadinfo->shdr[i].sh_flags & SHF_WRITE) != 0) + { +# if defined(CONFIG_ARCH_USE_DATA_HEAP) + up_dataheap_free((FAR void *)loadinfo->sectalloc[i]); +# else + kumm_free((FAR void *)loadinfo->sectalloc[i]); +# endif + } + else + { +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) + up_textheap_free((FAR void *)loadinfo->sectalloc[i]); +# else + kumm_free((FAR void *)loadinfo->sectalloc[i]); +# endif + } + } + + kmm_free(loadinfo->sectalloc); + loadinfo->sectalloc = 0; +# endif #endif /* Clear out all indications of the allocated address environment */ diff --git a/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index bd6830df92..57ec52dcb2 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -674,8 +674,28 @@ int elf_bind(FAR struct elf_loadinfo_s *loadinfo, * contents to memory and invalidating the I cache). */ - up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); - up_coherent_dcache(loadinfo->dataalloc, loadinfo->datasize); + if (loadinfo->textsize > 0) + { + up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); + } + + if (loadinfo->datasize > 0) + { + up_coherent_dcache(loadinfo->dataalloc, loadinfo->datasize); + } + +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + for (i = 0; loadinfo->ehdr.e_type == ET_REL && i < loadinfo->ehdr.e_shnum; + i++) + { + if (loadinfo->sectalloc[i] == 0) + { + continue; + } + + up_coherent_dcache(loadinfo->sectalloc[i], loadinfo->shdr[i].sh_size); + } +# endif #endif diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index 408fba0991..a3d1b0d1c7 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -64,6 +64,69 @@ * Private Functions ****************************************************************************/ +#if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) && !defined(CONFIG_ARCH_ADDRENV) +static int elf_section_alloc(FAR struct elf_loadinfo_s *loadinfo, + FAR Elf_Shdr *shdr, uint8_t idx) +{ + if (loadinfo->ehdr.e_type != ET_REL) + { + return -EINVAL; + } + + if (loadinfo->sectalloc == NULL) + { + /* Allocate memory info for all sections */ + + loadinfo->sectalloc = kmm_zalloc(sizeof(uintptr_t) * + loadinfo->ehdr.e_shnum); + if (loadinfo->sectalloc == NULL) + { + return -ENOMEM; + } + } + + elf_sectname(loadinfo, shdr); + if ((shdr->sh_flags & SHF_WRITE) != 0) + { +# ifdef CONFIG_ARCH_USE_DATA_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_dataheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)kumm_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->dataalloc == 0) + { + loadinfo->dataalloc = loadinfo->sectalloc[idx]; + } + } + else + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_textheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)kumm_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->textalloc == 0) + { + loadinfo->textalloc = loadinfo->sectalloc[idx]; + } + } + + return OK; +} +#endif + /**************************************************************************** * Name: elf_elfsize * @@ -104,6 +167,13 @@ static void elf_elfsize(FAR struct elf_loadinfo_s *loadinfo) #endif ) { +#if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) && !defined(CONFIG_ARCH_ADDRENV) + if (elf_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + datasize = _ALIGN_UP(datasize, shdr->sh_addralign); datasize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->dataalign < shdr->sh_addralign) @@ -113,6 +183,13 @@ static void elf_elfsize(FAR struct elf_loadinfo_s *loadinfo) } else { +#if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) && !defined(CONFIG_ARCH_ADDRENV) + if (elf_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + textsize = _ALIGN_UP(textsize, shdr->sh_addralign); textsize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->textalign < shdr->sh_addralign) @@ -181,7 +258,7 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { FAR uint8_t *text = (FAR uint8_t *)loadinfo->textalloc; FAR uint8_t *data = (FAR uint8_t *)loadinfo->dataalloc; - FAR uint8_t **pptr; + FAR uint8_t **pptr = NULL; int ret; int i; @@ -193,6 +270,23 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + /* SHF_ALLOC indicates that the section requires memory during + * execution. + */ + + if ((shdr->sh_flags & SHF_ALLOC) == 0) + { + continue; + } + +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + pptr = (FAR uint8_t **)&loadinfo->sectalloc[i]; + } + else +#endif + /* SHF_WRITE indicates that the section address space is write- * able */ @@ -262,7 +356,9 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) continue; } +#ifndef CONFIG_ARCH_USE_SEPARATED_SECTION *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, shdr->sh_addralign); +#endif /* SHT_NOBITS indicates that there is no data in the file for the * section. @@ -296,9 +392,16 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) shdr->sh_addr = (uintptr_t)*pptr; +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type != ET_REL) + { + *pptr += ELF_ALIGNUP(shdr->sh_size); + } +#else /* Setup the memory pointer for the next time through the loop */ *pptr += ELF_ALIGNUP(shdr->sh_size); +#endif } return OK; diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 25171be094..184cfaebc8 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -771,12 +771,17 @@ void up_extraheaps_init(void); * Name: up_textheap_memalign * * Description: - * Allocate memory for text sections with the specified alignment. + * Allocate memory for text with the specified alignment and sectname. * ****************************************************************************/ #if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) +FAR void *up_textheap_memalign(FAR const char *sectname, + size_t align, size_t size); +# else FAR void *up_textheap_memalign(size_t align, size_t size); +# endif #endif /**************************************************************************** @@ -851,12 +856,17 @@ void up_textheap_data_sync(void); * Name: up_dataheap_memalign * * Description: - * Allocate memory for data sections with the specified alignment. + * Allocate memory for data with the specified alignment and sectname. * ****************************************************************************/ #if defined(CONFIG_ARCH_USE_DATA_HEAP) +# if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) +FAR void *up_dataheap_memalign(FAR const char *sectname, + size_t align, size_t size); +# else FAR void *up_dataheap_memalign(size_t align, size_t size); +# endif #endif /**************************************************************************** diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h index 9fe9c47ed5..118c483627 100644 --- a/include/nuttx/binfmt/binfmt.h +++ b/include/nuttx/binfmt/binfmt.h @@ -69,6 +69,10 @@ struct binary_s main_t entrypt; /* Entry point into a program module */ FAR void *mapped; /* Memory-mapped, address space */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + FAR void **sectalloc; /* All sections memory allocated */ + uint16_t nsect; /* Number of sections */ +#endif FAR void *alloc[BINFMT_NALLOC]; /* Allocated address spaces */ #ifdef CONFIG_BINFMT_CONSTRUCTORS diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h index 7c32f5ff12..0dea9ae448 100644 --- a/include/nuttx/binfmt/elf.h +++ b/include/nuttx/binfmt/elf.h @@ -79,6 +79,10 @@ struct elf_loadinfo_s * after the ELF module has been loaded. */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + FAR uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ +#endif + uintptr_t textalloc; /* .text memory allocated when ELF file was loaded */ uintptr_t dataalloc; /* .bss/.data memory allocated when ELF file was loaded */ size_t textsize; /* Size of the ELF .text memory allocation */ diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index aa35b26088..8ca35e84ae 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -191,6 +191,10 @@ struct mod_loadinfo_s * after the module has been loaded. */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ +#endif + uintptr_t textalloc; /* .text memory allocated when module was loaded */ uintptr_t datastart; /* Start of.bss/.data memory in .text allocation */ size_t textsize; /* Size of the module .text memory allocation */ diff --git a/libs/libc/dlfcn/lib_dlopen.c b/libs/libc/dlfcn/lib_dlopen.c index 357271ff80..a9921ccdf9 100644 --- a/libs/libc/dlfcn/lib_dlopen.c +++ b/libs/libc/dlfcn/lib_dlopen.c @@ -89,6 +89,14 @@ static void dldump_loadinfo(FAR struct mod_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; binfo("Sections %d:\n", i); +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + binfo(" sh_name: %08x\n", shdr->sh_name); binfo(" sh_type: %08x\n", shdr->sh_type); binfo(" sh_flags: %08x\n", shdr->sh_flags); diff --git a/libs/libc/modlib/modlib_bind.c b/libs/libc/modlib/modlib_bind.c index b7202d8490..89443250e4 100644 --- a/libs/libc/modlib/modlib_bind.c +++ b/libs/libc/modlib/modlib_bind.c @@ -964,8 +964,28 @@ int modlib_bind(FAR struct module_s *modp, * contents to memory and invalidating the I cache). */ - up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); - up_coherent_dcache(loadinfo->datastart, loadinfo->datasize); + if (loadinfo->textsize > 0) + { + up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); + } + + if (loadinfo->datasize > 0) + { + up_coherent_dcache(loadinfo->datastart, loadinfo->datasize); + } + +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + for (i = 0; loadinfo->ehdr.e_type == ET_REL && i < loadinfo->ehdr.e_shnum; + i++) + { + if (loadinfo->sectalloc[i] == 0) + { + continue; + } + + up_coherent_dcache(loadinfo->sectalloc[i], loadinfo->shdr[i].sh_size); + } +#endif return ret; } diff --git a/libs/libc/modlib/modlib_load.c b/libs/libc/modlib/modlib_load.c index 8e1200863f..26748ed2ae 100644 --- a/libs/libc/modlib/modlib_load.c +++ b/libs/libc/modlib/modlib_load.c @@ -56,6 +56,69 @@ * Private Functions ****************************************************************************/ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION +static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, + FAR Elf_Shdr *shdr, uint8_t idx) +{ + if (loadinfo->ehdr.e_type != ET_REL) + { + return -EINVAL; + } + + if (loadinfo->sectalloc == NULL) + { + /* Allocate memory info for all sections */ + + loadinfo->sectalloc = lib_zalloc(sizeof(uintptr_t) * + loadinfo->ehdr.e_shnum); + if (loadinfo->sectalloc == NULL) + { + return -ENOMEM; + } + } + + modlib_sectname(loadinfo, shdr); + if ((shdr->sh_flags & SHF_WRITE) != 0) + { +# ifdef CONFIG_ARCH_USE_DATA_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_dataheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)lib_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->datastart == 0) + { + loadinfo->datastart = loadinfo->sectalloc[idx]; + } + } + else + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_textheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)lib_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->textalloc == 0) + { + loadinfo->textalloc = loadinfo->sectalloc[idx]; + } + } + + return 0; +} +#endif + /**************************************************************************** * Name: modlib_elfsize * @@ -70,7 +133,10 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo) size_t datasize = 0; int i; - /* Accumulate the size each section into memory that is marked SHF_ALLOC */ + /* Accumulate the size each section into memory that is marked SHF_ALLOC + * if CONFIG_ARCH_USE_SEPARATED_SECTION is enabled, allocate + * (and zero) memory for the each section. + */ if (loadinfo->ehdr.e_phnum > 0) { @@ -118,6 +184,13 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo) #endif ) { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (modlib_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + datasize = _ALIGN_UP(datasize, shdr->sh_addralign); datasize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->dataalign < shdr->sh_addralign) @@ -127,6 +200,13 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo) } else { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (modlib_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + textsize = _ALIGN_UP(textsize, shdr->sh_addralign); textsize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->textalign < shdr->sh_addralign) @@ -161,7 +241,6 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) { FAR uint8_t *text = (FAR uint8_t *)loadinfo->textalloc; FAR uint8_t *data = (FAR uint8_t *)loadinfo->datastart; - FAR uint8_t **pptr; int ret; int i; @@ -204,6 +283,7 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + FAR uint8_t **pptr = NULL; /* SHF_ALLOC indicates that the section requires memory during * execution @@ -214,25 +294,35 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) continue; } - /* SHF_WRITE indicates that the section address space is write- - * able - */ - - if ((shdr->sh_flags & SHF_WRITE) != 0 -#ifdef CONFIG_ARCH_HAVE_TEXT_HEAP_WORD_ALIGNED_READ - || (shdr->sh_flags & SHF_EXECINSTR) == 0 +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + pptr = (FAR uint8_t **)&loadinfo->sectalloc[i]; + } #endif - ) - { - pptr = &data; - } - else - { - pptr = &text; - } - *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, - shdr->sh_addralign); + if (pptr == NULL) + { + /* SHF_WRITE indicates that the section address space is + * writeable + */ + + if ((shdr->sh_flags & SHF_WRITE) != 0 +#ifdef CONFIG_ARCH_HAVE_TEXT_HEAP_WORD_ALIGNED_READ + || (shdr->sh_flags & SHF_EXECINSTR) == 0 +#endif + ) + { + pptr = &data; + } + else + { + pptr = &text; + } + + *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, + shdr->sh_addralign); + } /* SHT_NOBITS indicates that there is no data in the file for the * section. @@ -267,9 +357,16 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) shdr->sh_addr = (uintptr_t)*pptr; +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type != ET_REL) + { + *pptr += ELF_ALIGNUP(shdr->sh_size); + } +#else /* Setup the memory pointer for the next time through the loop */ *pptr += ELF_ALIGNUP(shdr->sh_size); +#endif } } @@ -324,18 +421,19 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->ehdr.e_type == ET_REL) { +#ifndef CONFIG_ARCH_USE_SEPARATED_SECTION if (loadinfo->textsize > 0) { -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# ifdef CONFIG_ARCH_USE_TEXT_HEAP loadinfo->textalloc = (uintptr_t) up_textheap_memalign(loadinfo->textalign, loadinfo->textsize + loadinfo->segpad); -#else +# else loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign, loadinfo->textsize + loadinfo->segpad); -#endif +# endif if (!loadinfo->textalloc) { berr("ERROR: Failed to allocate memory for the module text\n"); @@ -346,14 +444,14 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->datasize > 0) { -#if defined(CONFIG_ARCH_USE_DATA_HEAP) +# ifdef CONFIG_ARCH_USE_DATA_HEAP loadinfo->datastart = (uintptr_t) up_dataheap_memalign(loadinfo->dataalign, loadinfo->datasize); -#else +# else loadinfo->datastart = (uintptr_t)lib_memalign(loadinfo->dataalign, loadinfo->datasize); -#endif +# endif if (!loadinfo->datastart) { berr("ERROR: Failed to allocate memory for the module data\n"); @@ -361,6 +459,7 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) goto errout_with_buffers; } } +#endif } else { diff --git a/libs/libc/modlib/modlib_unload.c b/libs/libc/modlib/modlib_unload.c index ebd88404de..02c8646855 100644 --- a/libs/libc/modlib/modlib_unload.c +++ b/libs/libc/modlib/modlib_unload.c @@ -62,6 +62,33 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->ehdr.e_type != ET_DYN) { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + int i; + + for (i = 0; loadinfo->sectalloc[i] != 0 && + i < loadinfo->ehdr.e_shnum; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember((FAR void *)loadinfo->sectalloc[i])) + { + up_textheap_free((FAR void *)loadinfo->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember((FAR void *)loadinfo->sectalloc[i])) + { + up_dataheap_free((FAR void *)loadinfo->sectalloc[i]); + continue; + } +# endif + + lib_free((FAR void *)loadinfo->sectalloc[i]); + } + + lib_free(loadinfo->sectalloc); +#else if (loadinfo->textalloc != 0) { #if defined(CONFIG_ARCH_USE_TEXT_HEAP) @@ -79,6 +106,7 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) lib_free((FAR void *)loadinfo->datastart); #endif } +#endif } else { diff --git a/sched/module/mod_insmod.c b/sched/module/mod_insmod.c index 25539f381b..a020089450 100644 --- a/sched/module/mod_insmod.c +++ b/sched/module/mod_insmod.c @@ -90,6 +90,14 @@ static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; binfo("Sections %d:\n", i); +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + binfo(" sh_name: %08x\n", shdr->sh_name); binfo(" sh_type: %08x\n", shdr->sh_type); binfo(" sh_flags: %08jx\n", (uintmax_t)shdr->sh_flags);